Recently, I got me a new (well, release date was some July 2016) Massduino with an MD-328 controller manufactured by INHAOS, GuangDong China.
You will find a lot of adverts for it, but hardly any documentation.
At least, you are warned, there is no real EEPROM onboard (like on the DUE and some other controllers) but it can be emulated and actually is part of the FLASH memory.
After having written data to the EEPROM you can read it with pgm_read_byte with an offset address of 0x7800.
I did not find any figures about maximum rewrite cycles for the MD-328, but as the EEPROM is part of the FLASH the same restrictions will apply to the EEPROM whereas the Atmel EEPROM can be reprogrammed ten times more often.
Anyway, this concept offers to use a Harvard architecture as a von Neumann type.
(Many users have been asking how to write to the ATmega328-FLASH at runtime.)
You can write opcodes to the EEPROM (at runtime!) and let them execute whenever you want.
Of course, the compiler won't do it for you, you have to look up the codes yourself.
You even could connect the Massduino to the ethernet and download code dynamically, store it in EEPROM and execute it with a simple CALL instruction.
I tried it, and it worked immediately:
#include <EEPROM.h>
const word RET = 0x9508;
const word SBI = 0x9A00;
const word CBI = 0x9800;
const word NOP = 0x0000; // just for fun
const char port = 'B';
const byte bit = 0;
int adr = 0;
void setup() {
Serial.begin(9600);
Serial.println(__FILE__);
switch (port) {
case 'B': pinMode( 8 + bit, OUTPUT);
case 'C': pinMode(14 + bit, OUTPUT);
case 'D': pinMode( bit, OUTPUT);
}
// writing machine language opcodes to EEPROM:
storeOpcode(SBI, port, bit); // LED on
storeOpcode(RET); // last instruction of subroutine
delay(1000);
Serial.println("jump to subroutine located in EEPROM");
asm("CALL 0x7800");
Serial.println("after returning from subroutine");
delay(1000);
storeOpcode(CBI, port, bit); // LED off
storeOpcode(NOP);
storeOpcode(RET); // last instruction of part two
delay(1000);
Serial.println("again jump to subroutine:");
asm("CALL 0x7804");
Serial.println("again returning from subroutine.\nready.");
}
void loop() {}
void storeOpcode(word opCode, char a, byte b) {
byte p;
switch (a) {
case 'B': p = 5; break;
case 'C': p = 8; break;
case 'D': p = 11; break;
}
storeOpcode(opCode + 8 * p + b);
}
void storeOpcode(word opCode) {
byte L = lowByte(opCode);
byte H = highByte(opCode);
Serial.print(adr);
hexByte(adr++, L);
hexByte(adr++, H);
Serial.println();
}
void hexByte(int adr, byte b) {
// write to EEPROM only if necessary:
if (EEPROM.read(adr) != b) EEPROM.write(adr, b);
Serial.print(" ");
if (b < 0x10) Serial.print(0);
Serial.print(b, HEX);
}