Skip to content

Instantly share code, notes, and snippets.

@harelabb
Created December 14, 2019 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save harelabb/c714b7bc6a8d1ae70fda10d97f7812ab to your computer and use it in GitHub Desktop.
Save harelabb/c714b7bc6a8d1ae70fda10d97f7812ab to your computer and use it in GitHub Desktop.
Arduino Mega sketch to program EEPROM for RC switch code
#include <Arduino.h>
constexpr bool dry_run {false};
constexpr bool do_program {true};
// codes
constexpr uint32_t on_code {38909585};
constexpr uint32_t off_code {39916949};
// protocol
constexpr int pulse_length {450}; //RCswitch reports too high value
constexpr uint8_t on_bit[] {2, 1};
constexpr uint8_t off_bit[] {1, 2};
constexpr uint8_t sync_bit[] {1, 10};
constexpr int code_length {28};
constexpr uint8_t off_address {0x00};
constexpr uint8_t on_address {0x40};
constexpr int transmit_pin {5};
constexpr int serial_speed {9600};
constexpr int on_off_delay {1000};
// ------- most configuration above here -----------
constexpr uint8_t ones(int n) {
return n <= 1 ? 1 : (1 << (n-1)) | ones(n-1);
}
template <typename T>
constexpr T diff(T a, T b) {
return a > b ? a - b : b - a;
}
constexpr int npulse {on_bit[0] + on_bit[1]};
constexpr int nsync {sync_bit[0] + sync_bit[1]};
constexpr int code_size {nsync + code_length * npulse};
constexpr int code_bytes {(code_size + 7) / 8};
constexpr int repeat {diff(on_address, off_address) / code_bytes};
constexpr uint8_t off {ones(off_bit[0])};
constexpr uint8_t on {ones(on_bit[0])};
constexpr uint8_t sync {ones(sync_bit[0])};
// ------------------------------------------------------------------------
// Arduino Mega parallel EEPROM programmer
// can program 256 entries (8 bit addresses)
// PORTA for address pins 22-29
// PORTC for data pins 37-30
// DRY_RUN can be used for storing data in Arduino memory
// instead of an actual EEPROM.
template <bool DRY_RUN = false>
class Eeprom {
static constexpr int CE{2};
static constexpr int OE{3};
static constexpr int WE{4};
uint8_t eeprom[DRY_RUN ? 256 : 1];
#ifndef ARDUINO_AVR_MEGA2560
static_assert(DRY_RUN, "Arduino Mega needed if not dry_run");
int DDRA, PORTA;
#endif
public:
void begin() {
pinMode(CE, OUTPUT);
pinMode(WE, OUTPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, HIGH);
digitalWrite(WE, HIGH);
digitalWrite(CE, HIGH);
DDRC = 0x00;
DDRA = 0xff;
PORTA = 0x00;
delay(1);
}
void end() {
DDRA = 0xff;
DDRC = 0xff;
PORTA = 0;
PORTC = 0;
}
void writeByte(uint8_t data,
uint8_t address) {
digitalWrite(OE, HIGH);
digitalWrite(WE, HIGH);
digitalWrite(CE, LOW);
DDRC = 0xff;
PORTA = address;
PORTC = data;
digitalWrite(WE, LOW);
delayMicroseconds(10);
digitalWrite(WE, HIGH);
digitalWrite(CE, HIGH);
}
uint8_t readByte(uint8_t address) {
digitalWrite(OE, HIGH);
digitalWrite(WE, HIGH);
digitalWrite(CE, LOW);
DDRC= 0x00;
PORTA = address;
digitalWrite(OE, LOW);
delayMicroseconds(1);
uint8_t data {PINC};
digitalWrite(OE, HIGH);
digitalWrite(CE, HIGH);
return data;
}
};
// Alternative versions for dry run
template<>
void Eeprom<true>::begin() {}
template<>
void Eeprom<true>::end() {}
template<>
void Eeprom<true>::writeByte(uint8_t data,
uint8_t address) {
eeprom[address] = data;
}
template <>
uint8_t Eeprom<true>::readByte(uint8_t address) {
return eeprom[address];
}
Eeprom<dry_run> eeprom;
// ------------------------------------------------------------------------
class Reader {
int32_t bit_count {0};
uint8_t bits {0};
uint8_t address;
public:
explicit Reader(uint8_t start_address)
: address(start_address) {}
uint8_t getAddress() const {
return address;
}
bool readBit() {
if (bit_count++ % 8 == 0) {
bits = eeprom.readByte(address++);
bit_count = 1;
delay(20);
}
bool bit = bits & 1;
bits >>= 1;
return bit;
}
void skipSync() {
for (int b {0}; b < nsync; ++b) {
(void) readBit();
}
}
bool readCodeBit() {
uint8_t code_bit {0};
for (int b {0}; b < npulse; ++b) {
if (readBit()) {
code_bit |= (1 << b);
}
}
if (code_bit != on && code_bit != off) {
Serial.print("Illegal code bit: ");
Serial.println(code_bit, HEX);
}
return code_bit == on;
}
uint32_t readCode() {
skipSync();
uint32_t code {0};
for (auto c {code_length}; c--;) {
if (readCodeBit()) {
code |= (1L << c);
}
}
return code;
}
};
class Writer {
int32_t bit_count {0};
uint8_t bits {0};
uint8_t address;
public:
explicit Writer(uint8_t start_address)
: address(start_address) {}
~Writer() {
if (bit_count != 0) {
eeprom.writeByte(bits, address);
}
}
uint8_t getAddress() const {
return bit_count == 0 ? address : address + 1;
}
void writeBit(bool bit) {
if (bit) {
bits |= (1 << bit_count);
}
if (++bit_count == 8) {
eeprom.writeByte(bits, address++);
delay(20);
bits = bit_count = 0;
}
}
void writeCodeBit(bool bit) {
uint8_t code_bit {bit ? on : off};
for (int b {0}; b < npulse; ++b) {
writeBit(code_bit & (1 << b));
}
}
void writeSync() {
for (int b {0}; b < nsync; ++b) {
writeBit(sync & (1 << b));
}
}
void writeCode(uint32_t code) {
writeSync();
for (auto c {code_length}; c--;) {
writeCodeBit(code & (1L << c));
}
}
};
// ------------------------------------------------------------------------
bool verifyEeprom(uint32_t expected,
uint8_t address) {
Reader reader(address);
for (int r {0}; r < repeat; ++r) {
uint32_t code {reader.readCode()};
Serial.println(code, HEX);
if (code != expected) {
Serial.println("Code verification failed");
return false;
}
}
Serial.println(reader.getAddress(), HEX);
return true;
}
void writeEeprom(uint32_t code,
uint8_t address) {
Writer writer(address);
Serial.println(code, HEX);
for (int r {0}; r < repeat; ++r) {
writer.writeCode(code);
}
Serial.println(writer.getAddress(), HEX);
}
void setup() {
Serial.begin(serial_speed);
pinMode(transmit_pin, OUTPUT);
eeprom.begin();
if (!dry_run && !do_program) {
return;
}
// Write the codes to the EEPROM
Serial.println("clearing");
for (int i {0}; i <= 0xff; ++i) {
eeprom.writeByte(0, i);
}
Serial.println("writing");
writeEeprom(off_code, off_address);
writeEeprom(on_code, on_address);
Serial.println("verifying");
if (!verifyEeprom(off_code, off_address) ||
!verifyEeprom(on_code, on_address)) {
eeprom.end();
for (;;) {}
}
}
void sendCode(uint8_t address,
uint8_t nbytes) {
// Sends the code stored in the EEPROM to the transmitter
for (uint8_t n {0}; n < nbytes; ++n) {
uint8_t bits {eeprom.readByte(address++)};
for (uint8_t b {0}; b < 8; ++b) {
digitalWrite(transmit_pin, bits & 1 ? HIGH : LOW);
delayMicroseconds(pulse_length);
bits >>= 1;
}
}
}
void loop() {
constexpr uint8_t addresses[] {
off_address, on_address, off_address, on_address};
for (auto adr : addresses) {
Serial.println(adr == on_address ? "on" : "off");
sendCode(adr, diff(on_address, off_address));
delay(on_off_delay);
}
eeprom.end();
for(;;) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment