Skip to content

Commit

Permalink
Generate .ino flashing script in build
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoskal committed Dec 26, 2016
1 parent f7a3e92 commit a013c76
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 7 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ $(BUILD_PATH)/%.o: src/%.c $(wildcard inc/*.h boards/*/*.h)
$(BUILD_PATH)/%.o: $(BUILD_PATH)/%.c
@$(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@

$(BUILD_PATH)/selfdata.c: $(EXECUTABLE)
node scripts/gendata.js $< > $@
$(BUILD_PATH)/selfdata.c: $(EXECUTABLE) scripts/gendata.js
node scripts/gendata.js $(BUILD_PATH) $(NAME).bin

clean:
rm -rf build
Expand Down
16 changes: 11 additions & 5 deletions scripts/gendata.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
let fs = require("fs")
let buf = fs.readFileSync(process.argv[2])
let buildPath = process.argv[2]
let binName = buildPath + "/" + process.argv[3]
let buf = fs.readFileSync(binName)
let tail = new Buffer(8192 - buf.length)
if (buf.length > 8192) {
console.error("Bootloader too big!")
console.log("Bootloader too big!") // make sure it ends up in the file
process.exit(1)
}
tail.fill(0)
Expand All @@ -22,7 +23,7 @@ function addCrc(ptr, crc) {
}

let size = buf.length
let s = "#include <stdint.h>\n"
let s = ""
s += "const uint8_t bootloader[" + size + "] __attribute__ ((aligned (4))) = {"
function tohex(v) {
return "0x" + ("00" + v.toString(16)).slice(-2) + ", "
Expand All @@ -41,5 +42,10 @@ for (let i = 0; i < size; ++i) {
}
}
s += "\n};\n"
s += "const uint16_t bootloader_crcs[] = {" + crcs + "};"
console.log(s)
s += "const uint16_t bootloader_crcs[] = {" + crcs + "};\n"

let selfdata = "#include <stdint.h>\n" + s
fs.writeFileSync(buildPath + "/selfdata.c", selfdata)

let sketch = fs.readFileSync("src/sketch.cpp", "utf8")
fs.writeFileSync(buildPath + "/bootloader.ino", s + "\n" + sketch)
166 changes: 166 additions & 0 deletions src/sketch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#define BOOTLOADER_K 8

static uint16_t crcCache[256];

#define CRC16POLY 0x1021

#define FLASH_ROW_SIZE (FLASH_PAGE_SIZE*4)

uint16_t add_crc(uint8_t ch, unsigned short crc0) {
if (!crcCache[1]) {
for (int ptr = 0; ptr < 256; ptr++) {
uint16_t crc = (int)ptr << 8;
for (uint16_t cmpt = 0; cmpt < 8; cmpt++) {
if (crc & 0x8000)
crc = crc << 1 ^ CRC16POLY;
else
crc = crc << 1;
}
crcCache[ptr] = crc;
}
}

return ((crc0 << 8) ^ crcCache[((crc0 >> 8) ^ ch) & 0xff]) & 0xffff;
}


uint8_t pageBuf[FLASH_ROW_SIZE];

#define NVM_USER_MEMORY ((volatile uint16_t *)NVMCTRL_USER)

static inline void wait_ready(void) {
while (NVMCTRL->INTFLAG.bit.READY == 0) {
}
}

void flash_erase_row(uint32_t *dst) {
wait_ready();
NVMCTRL->STATUS.reg = NVMCTRL_STATUS_MASK;

// Execute "ER" Erase Row
NVMCTRL->ADDR.reg = (uint32_t)dst / 2;
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
wait_ready();
}

void flash_write_words(uint32_t *dst, uint32_t *src, uint32_t n_words) {
// Set automatic page write
NVMCTRL->CTRLB.bit.MANW = 0;

while (n_words > 0) {
uint32_t len = min(FLASH_PAGE_SIZE >> 2, n_words);
n_words -= len;

// Execute "PBC" Page Buffer Clear
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
wait_ready();

// make sure there are no other memory writes here
// otherwise we get lock-ups

while (len--)
*dst++ = *src++;

// Execute "WP" Write Page
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP;
wait_ready();
}
}

void flash_write_row(uint32_t *dst, uint32_t *src) {
flash_erase_row(dst);
flash_write_words(dst, src, FLASH_ROW_SIZE / 4);
}


static inline void exec_cmd(uint32_t cmd) {
NVMCTRL->ADDR.reg = (uint32_t)NVM_USER_MEMORY / 2;
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | cmd;
while (NVMCTRL->INTFLAG.bit.READY == 0) {
}
}

void setBootProt(int v) {
uint32_t fuses[2];
fuses[0] = NVM_USER_MEMORY[0] | (NVM_USER_MEMORY[1] << 16);
fuses[1] = NVM_USER_MEMORY[2] | (NVM_USER_MEMORY[3] << 16);

uint32_t bootprot = (fuses[0] & NVMCTRL_FUSES_BOOTPROT_Msk) >> NVMCTRL_FUSES_BOOTPROT_Pos;

if (bootprot == v)
return;

fuses[0] = (fuses[0] & ~NVMCTRL_FUSES_BOOTPROT_Msk) | (v << NVMCTRL_FUSES_BOOTPROT_Pos);

NVMCTRL->CTRLB.bit.MANW = 1;

exec_cmd(NVMCTRL_CTRLA_CMD_EAR);
exec_cmd(NVMCTRL_CTRLA_CMD_PBC);

*((uint32_t *)NVMCTRL_AUX0_ADDRESS) = fuses[0];
*(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1) = fuses[1];

exec_cmd(NVMCTRL_CTRLA_CMD_WAP);

fuses[0] = NVM_USER_MEMORY[0] | (NVM_USER_MEMORY[1] << 16);
fuses[1] = NVM_USER_MEMORY[2] | (NVM_USER_MEMORY[3] << 16);

NVIC_SystemReset();
}

void mydelay(int ms) {
ms <<= 13;
while (ms--) {
asm("nop");
}
}

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
setBootProt(7);

if (8 << NVMCTRL->PARAM.bit.PSZ != FLASH_PAGE_SIZE)
while(1) {}

__disable_irq();

setBootProt(7); // 0k

const uint8_t *ptr = bootloader;
int i;

for (i = 0; i < BOOTLOADER_K; ++i) {
int crc = 0;
for (int j = 0; j < 1024; ++j) {
crc = add_crc(*ptr++, crc);
}
if (bootloader_crcs[i] != crc) {
while(1){}
}
}

for (i = 0; i < BOOTLOADER_K * 1024; i += FLASH_ROW_SIZE) {
memcpy(pageBuf, &bootloader[i], FLASH_ROW_SIZE);
flash_write_row((uint32_t*)(void *)i, (uint32_t*)(void *)pageBuf);
}



while (1) {
digitalWrite(LED_BUILTIN, HIGH);
mydelay(100);
digitalWrite(LED_BUILTIN, LOW);
mydelay(200);

}



// erase first row of this updater app, so the bootloader doesn't start us again
// flash_erase_row((void *)i); - this seems to cause trouble

}

void loop() {
}

0 comments on commit a013c76

Please sign in to comment.