Move MYSBootloader to separate github repository
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
*.o
|
||||
*.elf
|
||||
@@ -1,66 +0,0 @@
|
||||
PROJECT = MyOtaBootloader
|
||||
INCLUDES = ../libraries/MySensors
|
||||
|
||||
MCU = atmega328p
|
||||
CLK = 16000000L
|
||||
|
||||
ISP_PORT = com5
|
||||
ISP_SPEED = 115200
|
||||
ISP_PROTOCOL = stk500v2
|
||||
ISP_MCU = m328p
|
||||
# HFUSE = D8 - 4096 byte boot
|
||||
ISP_HFUSE = D8
|
||||
# LFUSE = 4E - Low power resonator (16MHz), fast start, clkdiv/8
|
||||
ISP_LFUSE = FF
|
||||
# EFUSE = 06 - 1.8V brownout
|
||||
ISP_EFUSE = 06
|
||||
ISP_ARGS = -c$(ISP_PROTOCOL) -P$(ISP_PORT) -b$(ISP_SPEED) -p$(ISP_MCU)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
BINPATH = C:/Program Files (x86)/Arduino/hardware/tools/avr/bin/
|
||||
JAVAPATH = C:/Program Files/Java/jdk1.7.0_40/bin/
|
||||
JAVAC = $(JAVAPATH)javac.exe
|
||||
JAVA = $(JAVAPATH)java.exe
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
UNAME_P := $(shell uname -p)
|
||||
UNAME_M := $(shell uname -m)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
BINPATH = ../arduino/bin-linux64/bin/
|
||||
else ifneq ($(filter %86,$(UNAME_P)),)
|
||||
BINPATH = ../arduino/bin-linux32/bin/
|
||||
else ifneq ($(filter arm%,$(UNAME_M)),)
|
||||
BINPATH = /usr/bin/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS = -c -g -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls -Wall -mmcu=$(MCU) -DF_CPU=$(CLK) -std=gnu99
|
||||
LDFLAGS = -Os -Wl,--section-start=.text=0x7000 -nostartfiles -mmcu=$(MCU)
|
||||
|
||||
all: clean out
|
||||
|
||||
clean:
|
||||
- rm *.o
|
||||
- rm *.elf
|
||||
- rm *.hex
|
||||
|
||||
$(PROJECT).o: $(PROJECT).c
|
||||
"$(BINPATH)avr-gcc" $(CFLAGS) -I$(INCLUDES) $< -o $@
|
||||
|
||||
$(PROJECT).elf: $(PROJECT).o
|
||||
"$(BINPATH)avr-gcc" $(LDFLAGS) -o $@ $< -lm
|
||||
|
||||
$(PROJECT).hex: $(PROJECT).elf
|
||||
"$(BINPATH)avr-objcopy" -O ihex -R .eeprom $< $@
|
||||
|
||||
out: $(PROJECT).hex
|
||||
"$(BINPATH)avr-size" $(PROJECT).elf
|
||||
|
||||
load: clean out isp
|
||||
|
||||
isp: $(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -e -u -Ulock:w:0x3f:m -qq -Uefuse:w:0x$(ISP_EFUSE):m -Uhfuse:w:0x$(ISP_HFUSE):m -Ulfuse:w:0x$(ISP_LFUSE):m -Ulock:w:0x0f:m
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -V -q -s -Uflash:w:$(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS)
|
||||
@@ -1,213 +0,0 @@
|
||||
#include "MyOtaBootloader.h"
|
||||
|
||||
int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
|
||||
|
||||
volatile char dummy;
|
||||
|
||||
EMPTY_INTERRUPT(WDT_vect);
|
||||
|
||||
static uint16_t calcCRCrom (const void* ptr, uint16_t len) {
|
||||
uint16_t crc = ~0;
|
||||
for (uint16_t i = 0; i < len; ++i)
|
||||
crc = _crc16_update(crc, pgm_read_byte((uint16_t) ptr + i));
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint8_t validFirmware () {
|
||||
return calcCRCrom(0, fc.blocks * FIRMWARE_BLOCK_SIZE) == fc.crc;
|
||||
}
|
||||
|
||||
static void reboot() {
|
||||
wdt_enable(WDTO_15MS);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void startup() {
|
||||
if (validFirmware()) {
|
||||
wdt_disable();
|
||||
clock_prescale_set(orgClockDiv);
|
||||
((void(*)()) 0)();
|
||||
} else
|
||||
reboot();
|
||||
}
|
||||
|
||||
static void boot_program_page(uint32_t page, uint8_t *buf) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
eeprom_busy_wait();
|
||||
boot_page_erase(page);
|
||||
boot_spm_busy_wait();
|
||||
for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) {
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
boot_page_fill(page + i, w);
|
||||
}
|
||||
boot_page_write(page);
|
||||
boot_spm_busy_wait();
|
||||
boot_rww_enable();
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
static boolean sendWrite(MyMessage message) {
|
||||
return write(nc.parentNodeId, message.array, HEADER_SIZE + mGetLength(message), (message.destination == BROADCAST_ADDRESS));
|
||||
}
|
||||
|
||||
static uint8_t sendAndWait(uint8_t reqType, uint8_t resType) {
|
||||
msg.type = reqType;
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
sendWrite(msg);
|
||||
for (uint8_t j = 0; j < 20; j++) {
|
||||
wdt_reset();
|
||||
for (uint8_t j = 0; j < 100; j++) {
|
||||
wdt_reset();
|
||||
uint8_t pipe;
|
||||
boolean avail = available(&pipe);
|
||||
if (avail && pipe<=6) {
|
||||
read(rmsg.array,pipe);
|
||||
if(!(mGetVersion(rmsg) == PROTOCOL_VERSION))
|
||||
continue;
|
||||
if (rmsg.destination == nc.nodeId) {
|
||||
if (mGetCommand(rmsg) == C_INTERNAL) {
|
||||
if (rmsg.type == I_FIND_PARENT_RESPONSE) {
|
||||
if (rmsg.data[0] < nc.distance - 1) {
|
||||
nc.distance = rmsg.data[0] + 1;
|
||||
nc.parentNodeId = rmsg.sender;
|
||||
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId);
|
||||
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((mGetCommand(rmsg) == mGetCommand(msg)) && (rmsg.type == resType))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
delaym(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main () {
|
||||
asm volatile ("clr __zero_reg__");
|
||||
// switch to 4 MHz
|
||||
orgClockDiv = clock_prescale_get();
|
||||
clock_prescale_set(F_CPU_DIV);
|
||||
MCUSR = 0;
|
||||
// enable watchdog to avoid deadlock
|
||||
wdt_enable(WDTO_8S);
|
||||
|
||||
#ifdef LED_DEBUG
|
||||
// enable LEDs for debugging and blink once as visual "bootloader started" sign
|
||||
led_init();
|
||||
blink(LED_MBOTH, 250);
|
||||
#endif
|
||||
#ifdef UART_DEBUG
|
||||
// enable UART for debugging and send start message
|
||||
uart_init();
|
||||
uart_puts("Go\n");
|
||||
#endif
|
||||
|
||||
wdt_reset();
|
||||
// initialize RF module
|
||||
begin();
|
||||
wdt_reset();
|
||||
// Read settings from EEPROM
|
||||
eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(struct NodeConfig));
|
||||
wdt_reset();
|
||||
|
||||
msg.sender = nc.nodeId;
|
||||
msg.last = nc.nodeId;
|
||||
address(nc.nodeId);
|
||||
|
||||
msg.sensor = NODE_SENSOR_ID;
|
||||
mSetLength(msg, 0);
|
||||
mSetPayloadType(msg, P_STRING);
|
||||
mSetAck(msg,false);
|
||||
mSetVersion(msg, PROTOCOL_VERSION);
|
||||
|
||||
nc.distance = 255;
|
||||
mSetCommand(msg, C_INTERNAL);
|
||||
msg.destination = BROADCAST_ADDRESS;
|
||||
if (!sendAndWait(I_FIND_PARENT, I_FIND_PARENT_RESPONSE))
|
||||
// starting existing firmware if no parent responds (if firmware is valid)
|
||||
// reboot();
|
||||
startup();
|
||||
|
||||
msg.destination = GATEWAY_ADDRESS;
|
||||
|
||||
if (nc.nodeId == AUTO) {
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId));
|
||||
if (!sendAndWait(I_ID_REQUEST, I_ID_RESPONSE))
|
||||
reboot();
|
||||
if (mGetPayloadType(rmsg) == P_BYTE)
|
||||
nc.nodeId = rmsg.data[0];
|
||||
else if (mGetPayloadType(rmsg) == P_STRING)
|
||||
nc.nodeId = atoi(rmsg.data);
|
||||
if (nc.nodeId == AUTO)
|
||||
reboot();
|
||||
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId);
|
||||
msg.sender = nc.nodeId;
|
||||
msg.last = nc.nodeId;
|
||||
address(nc.nodeId);
|
||||
}
|
||||
|
||||
// Inform gateway that bootloader does not accept signed messages
|
||||
msg.type = I_REQUEST_SIGNING;
|
||||
mSetLength(msg, 1);
|
||||
msg.data[0] = 0;
|
||||
sendWrite(msg);
|
||||
|
||||
// Read settings from EEPROM
|
||||
eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
|
||||
|
||||
mSetPayloadType(msg,P_CUSTOM);
|
||||
|
||||
FirmwareConfigRequest *firmwareConfigRequest = (FirmwareConfigRequest *)msg.data;
|
||||
mSetLength(msg, sizeof(FirmwareConfigRequest));
|
||||
mSetCommand(msg, C_STREAM);
|
||||
firmwareConfigRequest->type = fc.type;
|
||||
firmwareConfigRequest->version = fc.version;
|
||||
if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE))
|
||||
// starting existing firmware if no firmware config response (if firmware is valid)
|
||||
// reboot();
|
||||
startup();
|
||||
FirmwareConfigResponse *firmwareConfigResponse = (FirmwareConfigResponse *)rmsg.data;
|
||||
if (firmwareConfigResponse->version == fc.version)
|
||||
if (firmwareConfigResponse->blocks == fc.blocks)
|
||||
if (firmwareConfigResponse->crc == fc.crc)
|
||||
if (validFirmware())
|
||||
startup();
|
||||
fc.type = firmwareConfigResponse->type;
|
||||
fc.version = firmwareConfigResponse->version;
|
||||
fc.blocks = firmwareConfigResponse->blocks;
|
||||
fc.crc = firmwareConfigResponse->crc;
|
||||
|
||||
FirmwareRequest *firmwareRequest = (FirmwareRequest *)msg.data;
|
||||
mSetLength(msg, sizeof(FirmwareRequest));
|
||||
firmwareRequest->type = fc.type;
|
||||
firmwareRequest->version = fc.version;
|
||||
for (uint16_t block = 0; block < fc.blocks; block++) {
|
||||
firmwareRequest->block = block;
|
||||
if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE))
|
||||
reboot();
|
||||
FirmwareResponse *firmwareResponse = (FirmwareResponse *)rmsg.data;
|
||||
uint8_t offset = (block * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE;
|
||||
memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
|
||||
if (offset == SPM_PAGESIZE - FIRMWARE_BLOCK_SIZE)
|
||||
boot_program_page((block * FIRMWARE_BLOCK_SIZE) - offset, progBuf);
|
||||
}
|
||||
|
||||
wdt_reset();
|
||||
|
||||
if (validFirmware()) {
|
||||
eeprom_write_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("fw ok\n");
|
||||
} else {
|
||||
uart_puts("fw nok\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
reboot();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
#ifndef MyOtaBootloader_H
|
||||
#define MyOtaBootloader_H
|
||||
|
||||
#include <avr/boot.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <util/crc16.h>
|
||||
|
||||
#include "MyMessage.h"
|
||||
#include "MySensor.h"
|
||||
#include "MyOtaBootloaderRF24.h"
|
||||
|
||||
#define FIRMWARE_BLOCK_SIZE 16
|
||||
|
||||
struct FirmwareConfig
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
} FirmwareConfigRequest;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
} FirmwareConfigResponse;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
} FirmwareRequest;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE];
|
||||
} FirmwareResponse;
|
||||
|
||||
static struct NodeConfig nc;
|
||||
static struct FirmwareConfig fc;
|
||||
static MyMessage msg;
|
||||
static MyMessage rmsg;
|
||||
|
||||
static clock_div_t orgClockDiv = 0;
|
||||
|
||||
static uint8_t progBuf[SPM_PAGESIZE];
|
||||
|
||||
#endif // MyOtaBootloader_H
|
||||
@@ -1,210 +0,0 @@
|
||||
:1070000011E0A0E0B1E0E8EFFCE702C005900D92CE
|
||||
:10701000A030B107D9F711E0A0E0B1E001C01D92A6
|
||||
:10702000A83DB107E1F711248091610090E08F70D5
|
||||
:107030009070909301018093000182E090E020E83D
|
||||
:107040000FB6F89420936100809361000FBE14BEC8
|
||||
:1070500029E288E190E00FB6F894A895809360004B
|
||||
:107060000FBE20936000A8951092CF011092D0011E
|
||||
:107070001092D1011092D2011092D3011092D4013A
|
||||
:107080001092D5011092D60184B18E6284B92498F1
|
||||
:1070900085B1857D85B92A9A8AE0B1D184E06FE512
|
||||
:1070A00015D281E06BE312D285E06CE40FD286E06A
|
||||
:1070B000DED1682F607D676286E008D280E0D7D19C
|
||||
:1070C000682F6C6080E002D287E060E7FFD12A98E9
|
||||
:1070D00081E095D180E5A2D183E7A0D12A9A81E011
|
||||
:1070E0008ED18DE1C4D1682F66608DE1EFD18CE146
|
||||
:1070F000BED1682F6F638CE1E9D182EEAAD181EE17
|
||||
:10710000A8D1F9D180E0B3D1682F6E7F80E0DED1C5
|
||||
:1071100082E00FEF1CEF21EE38EA48EA50E060E031
|
||||
:1071200070E0F6D1A89582E091E060E070E043E085
|
||||
:1071300050E02AEE39E369D5A89580910201809349
|
||||
:107140000E0180930D0143D22FEF20931301809104
|
||||
:10715000110192E0909310012093040188708360E4
|
||||
:107160008093110120930F0187E068E03ED38823CC
|
||||
:1071700009F41ED310920F01809102018F3F09F094
|
||||
:1071800038C081E00FEF1CEF21EE38EA48EA50E00A
|
||||
:1071900060E070E0BDD183E064E027D3882309F488
|
||||
:1071A000FBD280913201829586958770813019F4E7
|
||||
:1071B0008091350105C0882329F485E391E007D546
|
||||
:1071C00080930201809102018F3F09F4E5D2809102
|
||||
:1071D0000201F999FECF1FBA12BC11BC80BD0FB6D7
|
||||
:1071E000F894FA9AF99A0FBE80930E0180930D01DC
|
||||
:1071F000EED185E091E06BE171E048E050E02AEEED
|
||||
:1072000039E303D590911101987180911001877035
|
||||
:10721000806280931001946C90931101809105011C
|
||||
:1072200090910601909315018093140180910701BC
|
||||
:1072300090910801909317018093160180E061E01E
|
||||
:10724000D4D2882309F4B4D2209137013091380187
|
||||
:10725000809107019091080128173907C9F42091FE
|
||||
:10726000390130913A018091090190910A01281762
|
||||
:10727000390771F420913B0130913C0180910B0161
|
||||
:1072800090910C012817390719F451D2811190D22D
|
||||
:10729000409135015091360150930601409305010C
|
||||
:1072A0002091370130913801309308012093070174
|
||||
:1072B0008091390190913A0190930A0180930901DC
|
||||
:1072C00080913B0190913C0190930C0180930B01C4
|
||||
:1072D000F4E1EF2EF1E0FF2E8091100187708063C2
|
||||
:1072E00080931001509315014093140130931701BE
|
||||
:1072F00020931601C0E0D0E000E91FEFBB24B39457
|
||||
:10730000E5E0CE2E71E1D72E4DC0F701D583C483C1
|
||||
:1073100082E063E06AD2882309F43ED2902F90592C
|
||||
:107320009F77E92FF0E0E15BFE4FABE3B1E080E156
|
||||
:107330000D9001928150E1F7903709F030C03FB7CE
|
||||
:10734000F894F999FECF83E0F80180935700E8950F
|
||||
:1073500007B600FCFDCFA801AFE4B1E02C91119677
|
||||
:107360008C91119790E0982F8827820F911D12968B
|
||||
:10737000FA010C01B0925700E89511244E5F5F4F5F
|
||||
:10738000F1E0AF3CBF0751F7F801C0925700E89514
|
||||
:1073900007B600FCFDCFD0925700E8953FBF21967D
|
||||
:1073A000005F1F4F8091090190910A01C817D9070A
|
||||
:1073B00008F4ABCFA895BBD1882349F08BE191E0CD
|
||||
:1073C00065E071E048E050E021EF39E33AD4E4D1E0
|
||||
:1073D00080E090E0F999FECF92BD81BDF89A80B52A
|
||||
:1073E0000895F999FECF1FBA92BD81BD60BD0FB659
|
||||
:1073F000F894FA9AF99A0FBE08950000089590E063
|
||||
:107400000AC020E030E000002F5F3F4F41E0243F02
|
||||
:107410003407C9F79F5F9817A0F308950F931F9340
|
||||
:10742000182F00E0EADF17FD02C02B9801C02B9A4D
|
||||
:10743000E4DF2D9A83B1110F82958170182BDDDF67
|
||||
:107440002D98DBDF0F5F083069F7812F1F910F91B7
|
||||
:1074500008951F93182F2A9881E0D1DF812FDEDF56
|
||||
:10746000182F2A9A81E0CBDF812F1F9108951F9357
|
||||
:10747000182F2A9881E0C3DF812F8F71CFDF8FEF24
|
||||
:10748000CDDF182F2A9A81E0BADF812F1F9108954E
|
||||
:107490000F931F93CF93DF93182FEB01042F2A989C
|
||||
:1074A00081E0ADDF1F71812F8062B8DF182F03C02C
|
||||
:1074B0008991B4DF01500023D9F72A9A81E09FDF38
|
||||
:1074C000812FDF91CF911F910F9108950F931F93FB
|
||||
:1074D000182F062F2A9881E092DF1F71812F80627A
|
||||
:1074E0009DDF182F802F9ADF2A9A81E088DF812F75
|
||||
:1074F0001F910F91089580E0BADF81FD08C080E000
|
||||
:10750000B6DF682F626080E0E1DF85E078DF089514
|
||||
:107510007F928F929F92AF92BF92CF92DF92EF9223
|
||||
:10752000FF920F931F93DF93CF93CDB7DEB72897CA
|
||||
:107530000FB6F894DEBF0FBECDBF782E48015901BB
|
||||
:107540006A017B01882381F40093CF019092D001DE
|
||||
:107550002093D101B092D2014093D301D092D401B3
|
||||
:107560006093D501F092D60189829A82AB82BC8267
|
||||
:10757000CD82DE82EF82F88681E0871538F0872D94
|
||||
:10758000865FBE016F5F7F4F45E082DF82E06FDF85
|
||||
:1075900021E030E002C0220F331F7A94E2F7682F17
|
||||
:1075A000622B82E093DF28960FB6F894DEBF0FBE01
|
||||
:1075B000CDBFCF91DF911F910F91FF90EF90DF90A2
|
||||
:1075C000CF90BF90AF909F908F907F9008957F92C3
|
||||
:1075D0008F929F92AF92BF92CF92DF92EF92FF92E3
|
||||
:1075E0000F931F93DF93CF93CDB7DEB728970FB6D6
|
||||
:1075F000F894DEBF0FBECDBF8F3F09F483C0082FC4
|
||||
:1076000010E020E030E040E050E060E070E089838E
|
||||
:107610001A832B833C834D835E836F837887882412
|
||||
:107620003CEF932E21EEA22E98EAB92E88EAC82EBE
|
||||
:10763000DD24EE24FF24080D81E09981091708F06C
|
||||
:1076400080E0192D91E0AA819A1608F090E0E82FC9
|
||||
:10765000E10F81E0E11708F080E0982B1E2F2A2D22
|
||||
:1076600077247394BB81AB1608F07724920F81E0E6
|
||||
:10767000921708F080E0782A292F3B2D91E0EC81C9
|
||||
:10768000BE1608F090E0E72DE30F81E0E31708F065
|
||||
:1076900080E0982B3E2F4C2D77247394FD81CF16DC
|
||||
:1076A00008F07724940F81E0941708F080E0782A9E
|
||||
:1076B000492F5D2D91E08E81D81608F090E0E72DDE
|
||||
:1076C000E50F81E0E51708F080E0982B5E2F6E2D26
|
||||
:1076D00077247394AF81EA1608F07724960F81E03F
|
||||
:1076E000961708F080E0782A692F7F0C772D5901D2
|
||||
:1076F0006A01E92E80E00CDF81E09501A6016E2D84
|
||||
:10770000772D06DF28960FB6F894DEBF0FBECDBFEB
|
||||
:10771000CF91DF911F910F91FF90EF90DF90CF906D
|
||||
:10772000BF90AF909F908F907F9008951895409153
|
||||
:10773000090150910A0164E0440F551F6A95E1F771
|
||||
:10774000E0E0F0E02FEF3FEF19C084912827822F6F
|
||||
:1077500082958227082E869586958025082E869507
|
||||
:1077600080258770022E232F869507948795302DCC
|
||||
:10777000282706948795302528273196E417F507A2
|
||||
:1077800020F340E080910B0190910C0128173907FC
|
||||
:1077900009F441E0842F089528E088E190E00FB6D5
|
||||
:1077A000F894A895809360000FBE20936000FFCFEF
|
||||
:1077B000BEDF8823C1F088E10FB6F89480936000A3
|
||||
:1077C000109260000FBE809100019091010120E8AD
|
||||
:1077D0000FB6F89420936100809361000FBEE0E043
|
||||
:1077E000F0E009950895D8DF08952F923F924F92C7
|
||||
:1077F0005F926F927F928F929F92AF92BF92CF9241
|
||||
:10780000DF92EF92FF920F931F93DF93CF93CDB749
|
||||
:10781000DEB7E3970FB6F894DEBF0FBECDBF6BA700
|
||||
:10782000809312016624B9E02B2E312C2C0E3D1EC4
|
||||
:107830002E010894411C511CD101EDE0F1E081E2E0
|
||||
:1078400001900D928150E1F7109103017C842B850A
|
||||
:107850002AA751DE299881E0D2DD81EEFADD82EEA1
|
||||
:10786000F8DD80E004DE682F6E7F80E02FDE30E000
|
||||
:1078700040E050E060E070E080E090E01CA73DA7B1
|
||||
:107880004EA75FA768AB79AB8AAB9BAB8824ACEF04
|
||||
:107890009A2EF1EEAF2EE8EABE2E78EAC72EDD244E
|
||||
:1078A000EE24FF24012F080D81E0011708F080E08D
|
||||
:1078B000192D91E0EDA59E1608F090E0E82FE10F5C
|
||||
:1078C00081E0E11708F080E0982B1E2F2A2DE1E0DF
|
||||
:1078D000FEA5AF1608F0E0E0920F81E0921708F0E5
|
||||
:1078E00080E0E82B292F3B2D91E08FA5B81608F0FA
|
||||
:1078F00090E0E30F81E0E31708F080E0982B3E2F43
|
||||
:107900004C2DE1E0F8A9CF1608F0E0E0940F81E0FB
|
||||
:10791000941708F080E0E82B492F5D2D91E089A9AC
|
||||
:10792000D81608F090E0E50F81E0E51708F080E058
|
||||
:10793000982B5E2F6E2D81E0EAA9EE1608F080E00C
|
||||
:10794000E92FE60F91E0E61708F090E0892B8F0D04
|
||||
:1079500009831A832B833C834D835E83EF8388875F
|
||||
:107960008AE0B20145E094DD80E1B20145E090DDBE
|
||||
:10797000FAA5FF3F11F010EA01C010EB769476945F
|
||||
:10798000769427E0720E2A9881E039DD812F46DD5A
|
||||
:1079900081017101E70CF11C04C0F80181918F0194
|
||||
:1079A0003DDD0E151F05C9F72A9A81E028DD299AC9
|
||||
:1079B00081E025DD299881E022DD8FEF4ADD8073AB
|
||||
:1079C000E1F387E060E782DD84FF02C081EE41DD04
|
||||
:1079D00092DD80E04CDD682F616080E077DD87E03C
|
||||
:1079E00060E774DD0091CF011091D0012091D101A9
|
||||
:1079F0003091D2014091D3015091D4016091D501D1
|
||||
:107A00007091D601802F812B822B832B842B852B89
|
||||
:107A1000862B872B61F009831A832B833C834D834C
|
||||
:107A20005E836F8378878AE0B20145E031DD82EEC4
|
||||
:107A300010DD81EE0EDD299A81E0E1DCCC24A895F1
|
||||
:107A4000DD24A89587E113DD80FD96C08FEF01DD71
|
||||
:107A5000E82EE694F7E0EF22EF1609F48DC02A989D
|
||||
:107A600081E0CDDC80E6DADC8FEFD8DCF82E2A9AD4
|
||||
:107A700081E0C5DC20E22F1518F482EEEADCFF2459
|
||||
:107A80002A9881E0BCDC81E6C9DC0EE211E006C088
|
||||
:107A90008FEFC4DCF80181938F01FA94FF20C1F7C6
|
||||
:107AA0002A9A81E0ACDC87E060E710DD2A9881E06B
|
||||
:107AB000A6DC8E2D886AB2DC8E2DB0DC2A9A81E09D
|
||||
:107AC0009EDC809131018770823009F057C090911F
|
||||
:107AD000300180910201981709F04EC08091320167
|
||||
:107AE000682F70E0CB0187709070039709F034C065
|
||||
:107AF00080913301883009F02FC040913501242F47
|
||||
:107B0000332727FD30958091040190E001972817D5
|
||||
:107B1000390714F5242F2F5F2093040180912F0142
|
||||
:107B200080930301F999FECF1FBA41E050E052BDA6
|
||||
:107B300041BD80BD0FB6F894FA9AF99A0FBEF99933
|
||||
:107B4000FECF1FBA82E090E092BD81BD20BD0FB68E
|
||||
:107B5000F894FA9AF99A0FBE8091110190E0862765
|
||||
:107B6000972787709070892B39F4809133019BA5FA
|
||||
:107B7000891711F481E012C081E041DCD394E4E67E
|
||||
:107B8000DE1609F05ECFC394F4E1CF1609F057CFAB
|
||||
:107B900063942AE0621609F04FCE80E0E3960FB6B8
|
||||
:107BA000F894DEBF0FBECDBFCF91DF911F910F9133
|
||||
:107BB000FF90EF90DF90CF90BF90AF909F908F900D
|
||||
:107BC0007F906F905F904F903F902F900895FC01B1
|
||||
:107BD00088279927E89421912032E9F3293010F081
|
||||
:107BE0002E30C8F32B3241F02D3239F4689404C0A2
|
||||
:107BF0000E943D3E820F911D219120532A30C0F3F7
|
||||
:107C00001EF4909581959F4F0895A0E0B0E0EBE0C1
|
||||
:107C1000FEE30C944F3E7C01EB018A01690109C02F
|
||||
:107C2000CE012196F6010995F70181937F0101505C
|
||||
:107C3000104001151105A1F7CDB7DEB7E8E00C94AF
|
||||
:107C40006B3EA0E0B0E0E7E2FEE30C944F3EEC01B7
|
||||
:107C50007B018A01690109C0CE012196F70161917A
|
||||
:107C60007F01F60109950150104001151105A1F79A
|
||||
:107C7000CDB7DEB7E8E00C946B3E7AE0979F902D8D
|
||||
:107C8000879F802D910D112408952F923F924F923E
|
||||
:107C90005F926F927F928F929F92AF92BF92CF929C
|
||||
:107CA000DF92EF92FF920F931F93CF93DF93CDB7A5
|
||||
:107CB000DEB7CA1BDB0B0FB6F894DEBF0FBECDBF1D
|
||||
:107CC00009942A88398848885F846E847D848C84EE
|
||||
:107CD0009B84AA84B984C884DF80EE80FD800C81F7
|
||||
:107CE0001B81AA81B981CE0FD11D0FB6F894DEBFDA
|
||||
:087CF0000FBECDBFED010895A8
|
||||
:040000030000700089
|
||||
:00000001FF
|
||||
@@ -1,155 +0,0 @@
|
||||
#ifndef MyOtaBootloaderHW_H
|
||||
#define MyOtaBootloaderHW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
//#define LED_DEBUG
|
||||
//#define UART_DEBUG
|
||||
|
||||
// hardware
|
||||
// ********
|
||||
|
||||
#define F_CPU_DIV clock_div_4
|
||||
#define F_CPU_REAL F_CPU / (1 << F_CPU_DIV)
|
||||
#define UART_BAUD 9600UL
|
||||
#define DELAY_M 125 * (1 << F_CPU_DIV)
|
||||
|
||||
// boolean definition
|
||||
// ******************
|
||||
|
||||
typedef uint8_t bool;
|
||||
typedef uint8_t boolean;
|
||||
#define false 0x0
|
||||
#define true 0x1
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
|
||||
// delay
|
||||
// *****
|
||||
|
||||
static void delayu() {
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
static void delaym(uint8_t t) {
|
||||
uint8_t d;
|
||||
uint16_t a;
|
||||
for (d = 0; d < t; d++)
|
||||
for (a = 0; a < DELAY_M; a++)
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
// LED debug
|
||||
// *********
|
||||
|
||||
#ifdef LED_DEBUG
|
||||
#define LED_DDR DDRD
|
||||
#define LED_PORT PORTD
|
||||
#define LED_RED 6 // Arduino Pin 6 <-> Bit 6 of port D
|
||||
#define LED_GREEN 7 // Arduino Pin 7 <-> Bit 7 of port D
|
||||
#define LED_MRED (1 << LED_RED)
|
||||
#define LED_MGREEN (1 << LED_GREEN)
|
||||
#define LED_MBOTH (LED_MRED | LED_MGREEN)
|
||||
|
||||
static void led_init() {
|
||||
LED_DDR |= LED_MBOTH;
|
||||
LED_PORT &= ~LED_MBOTH;
|
||||
}
|
||||
|
||||
static void blink(uint8_t mask, uint16_t time) {
|
||||
LED_PORT |= mask;
|
||||
if (time > 0)
|
||||
{
|
||||
delaym(time);
|
||||
LED_PORT &= ~mask;
|
||||
delaym(time);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// UART debug
|
||||
// **********
|
||||
|
||||
#ifdef UART_DEBUG
|
||||
static void uart_init()
|
||||
{
|
||||
UCSR0A = _BV(U2X0); //Double speed mode USART0
|
||||
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
|
||||
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
UBRR0L = (uint8_t)( (F_CPU_REAL + UART_BAUD * 4L) / (UART_BAUD * 8L) - 1 );
|
||||
}
|
||||
|
||||
static void uart_putc(char ch) {
|
||||
while (!(UCSR0A & _BV(UDRE0)));
|
||||
UDR0 = ch;
|
||||
}
|
||||
|
||||
static void uart_puts(char *s)
|
||||
{
|
||||
while (*s)
|
||||
uart_putc(*s++);
|
||||
}
|
||||
|
||||
static void uart_puti(uint8_t i)
|
||||
{
|
||||
char s[5];
|
||||
itoa( i, s, 10 );
|
||||
uart_puts( s );
|
||||
}
|
||||
#endif
|
||||
|
||||
// SPI communication
|
||||
// *****************
|
||||
|
||||
#define SPI_DDR DDRB
|
||||
#define SPI_PORT PORTB
|
||||
#define SPI_PIN PINB
|
||||
#define SPI_SCLK 5 // Arduino Pin 13 <-> Bit 5 of port B
|
||||
#define SPI_MISO 4 // Arduino Pin 12 <-> Bit 4 of port B
|
||||
#define SPI_MOSI 3 // Arduino Pin 11 <-> Bit 3 of port B
|
||||
#define SPI_CSN 2 // Arduino Pin 10 <-> Bit 2 of port B
|
||||
#define SPI_CE 1 // Arduino Pin 9 <-> Bit 1 of port B
|
||||
|
||||
#define csnlow() SPI_PORT &= ~(1<<SPI_CSN);delaym(1)
|
||||
#define csnhigh() SPI_PORT |= (1<<SPI_CSN);delaym(1)
|
||||
#define celow() SPI_PORT &= ~(1<<SPI_CE);delaym(1)
|
||||
#define cehigh() SPI_PORT |= (1<<SPI_CE);delaym(1)
|
||||
|
||||
static void SPIinit()
|
||||
{
|
||||
SPI_DDR |= (1 << SPI_MOSI) + (1 << SPI_SCLK) + (1 << SPI_CE) + (1 << SPI_CSN);
|
||||
SPI_DDR &= ~(1 << SPI_MISO);
|
||||
SPI_PORT &= ~((1 << SPI_MOSI) + (1 << SPI_SCLK) + (1 << SPI_CE));
|
||||
SPI_PORT |= (1 << SPI_CSN);
|
||||
}
|
||||
|
||||
static uint8_t SPItransfer(uint8_t value)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i = 0 ;i < 8;i++) {
|
||||
delayu();
|
||||
if ((value & 0x80) == 0x00)
|
||||
SPI_PORT &= ~(1 << SPI_MOSI);
|
||||
else
|
||||
SPI_PORT |= (1 << SPI_MOSI);
|
||||
value = (value << 1); // shift next bit into MSB..
|
||||
delayu();
|
||||
SPI_PORT |= (1 << SPI_SCLK);
|
||||
value |= ((SPI_PIN >> SPI_MISO) & 0x01); // capture current MISO bit
|
||||
delayu();
|
||||
SPI_PORT &= ~(1 << SPI_SCLK);
|
||||
delayu();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint8_t spiTrans(uint8_t cmd){
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( cmd );
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // MyOtaBootloaderHW_H
|
||||
@@ -1,253 +0,0 @@
|
||||
#ifndef MyOtaBootloaderRF24_H
|
||||
#define MyOtaBootloaderRF24_H
|
||||
|
||||
#include "MyOtaBootloaderHW.h"
|
||||
#include "../libraries/MySensors/utility/nRF24L01.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// hardware-agnostic interface to transceiver
|
||||
// ******************************************
|
||||
// static void begin()
|
||||
// static void address(uint8_t addr)
|
||||
// static boolean write(uint8_t next, uint8_t* packet, uint8_t length, boolean multicast)
|
||||
// static bool available(uint8_t* pipe_num)
|
||||
// static void read(uint8_t* buf, uint8_t pipe)
|
||||
|
||||
typedef enum { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR } rf24_pa_dbm_e ;
|
||||
typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e;
|
||||
|
||||
uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */
|
||||
|
||||
static uint8_t read_register(uint8_t reg)
|
||||
{
|
||||
csnlow();
|
||||
SPItransfer( R_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
uint8_t result = SPItransfer(0xff);
|
||||
csnhigh();
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t write_registers(uint8_t reg, const uint8_t* buf, uint8_t len)
|
||||
{
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
while ( len-- )
|
||||
SPItransfer(*buf++);
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t write_register(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t status;
|
||||
csnlow();
|
||||
status = SPItransfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
SPItransfer(value);
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t read_payload(uint8_t* buf, uint8_t data_len)
|
||||
{
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("-> ");
|
||||
#endif
|
||||
uint8_t status;
|
||||
uint8_t* current = buf;
|
||||
csnlow();
|
||||
status = SPItransfer( R_RX_PAYLOAD );
|
||||
while ( data_len-- ) {
|
||||
*current = SPItransfer(0xFF);
|
||||
#ifdef UART_DEBUG
|
||||
uart_puti(*current);
|
||||
uart_putc(',');
|
||||
#endif
|
||||
current++;
|
||||
}
|
||||
csnhigh();
|
||||
#ifdef UART_DEBUG
|
||||
uart_putc('\n');
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
#define get_status() spiTrans(NOP)
|
||||
|
||||
static void powerUp(void)
|
||||
{
|
||||
if (!(read_register(CONFIG) & _BV(PWR_UP))){
|
||||
write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP));
|
||||
delaym(5);
|
||||
}
|
||||
}
|
||||
|
||||
#define convert_64_bit_to_byte_array(value, data) ((*(uint64_t *)(data)) = (uint64_t)(value))
|
||||
|
||||
static void startListening(void)
|
||||
{
|
||||
powerUp();
|
||||
write_register(CONFIG, read_register(CONFIG) | _BV(PRIM_RX));
|
||||
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
if (pipe0_reading_address){
|
||||
uint8_t addressa[8];
|
||||
convert_64_bit_to_byte_array(pipe0_reading_address, addressa);
|
||||
write_registers(RX_ADDR_P0, addressa, 5);
|
||||
}
|
||||
spiTrans(FLUSH_RX);
|
||||
spiTrans(FLUSH_TX);
|
||||
cehigh();
|
||||
}
|
||||
|
||||
static void stopListening(void)
|
||||
{
|
||||
celow();
|
||||
spiTrans(FLUSH_TX);
|
||||
spiTrans(FLUSH_RX);
|
||||
write_register(CONFIG, read_register(CONFIG) & ~_BV(PRIM_RX));
|
||||
}
|
||||
|
||||
static void write_payload(const uint8_t* buf, uint8_t data_len, const uint8_t writeType)
|
||||
{
|
||||
#ifdef UART_DEBUG
|
||||
uart_puts("<- ");
|
||||
#endif
|
||||
const uint8_t* current = buf;
|
||||
csnlow();
|
||||
SPItransfer(writeType);
|
||||
while ( data_len-- ) {
|
||||
#ifdef UART_DEBUG
|
||||
uart_puti(*current);
|
||||
uart_putc(',');
|
||||
#endif
|
||||
SPItransfer(*current++);
|
||||
}
|
||||
csnhigh();
|
||||
#ifdef UART_DEBUG
|
||||
uart_putc('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool writem( const uint8_t* buf, uint8_t len, const bool multicast )
|
||||
{
|
||||
write_payload( buf, len, multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD) ;
|
||||
cehigh();
|
||||
celow();
|
||||
while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { }
|
||||
uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
if( status & _BV(MAX_RT)){
|
||||
spiTrans(FLUSH_TX);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t getDynamicPayloadSize(void)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
csnlow();
|
||||
SPItransfer( R_RX_PL_WID );
|
||||
result = SPItransfer(0xff);
|
||||
csnhigh();
|
||||
if(result > 32) {
|
||||
spiTrans(FLUSH_RX);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool available(uint8_t* pipe_num)
|
||||
{
|
||||
if (!(read_register(FIFO_STATUS) & _BV(RX_EMPTY) )){
|
||||
if (pipe_num) {
|
||||
uint8_t status = get_status();
|
||||
*pipe_num = ( status >> RX_P_NO ) & 0b111;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void writeAckPayload(uint8_t pipe, const uint8_t* buf, uint8_t len)
|
||||
{
|
||||
const uint8_t* current = buf;
|
||||
uint8_t data_len = len;
|
||||
csnlow();
|
||||
SPItransfer(W_ACK_PAYLOAD | ( pipe & 0b111 ) );
|
||||
while ( data_len-- )
|
||||
SPItransfer(*current++);
|
||||
csnhigh();
|
||||
}
|
||||
|
||||
static void read( uint8_t* buf, uint8_t pipe ){
|
||||
read_payload(buf, getDynamicPayloadSize());
|
||||
write_register(STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS));
|
||||
writeAckPayload(pipe,&pipe, 1 );
|
||||
}
|
||||
|
||||
static void openWritingPipe(uint64_t value)
|
||||
{
|
||||
uint8_t valuea[8];
|
||||
convert_64_bit_to_byte_array(value, valuea);
|
||||
write_registers(RX_ADDR_P0, valuea, 5);
|
||||
write_registers(TX_ADDR, valuea, 5);
|
||||
}
|
||||
|
||||
static void openReadingPipe(uint8_t child, uint64_t address)
|
||||
{
|
||||
if (child == 0)
|
||||
pipe0_reading_address = address;
|
||||
uint8_t addressa[8];
|
||||
convert_64_bit_to_byte_array(address, addressa);
|
||||
if ( child < 2 )
|
||||
write_registers(RX_ADDR_P0 + child, addressa, 5);
|
||||
write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(ERX_P0 + child));
|
||||
}
|
||||
|
||||
static boolean write(uint8_t next, uint8_t* packet, uint8_t length, boolean multicast) {
|
||||
powerUp();
|
||||
stopListening();
|
||||
openWritingPipe(TO_ADDR(next));
|
||||
bool ok = writem(packet, length, multicast);
|
||||
startListening();
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void address(uint8_t addr)
|
||||
{
|
||||
if (addr != BROADCAST_ADDRESS) {
|
||||
openReadingPipe(WRITE_PIPE, TO_ADDR(addr));
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void begin(void)
|
||||
{
|
||||
pipe0_reading_address = 0;
|
||||
|
||||
SPIinit();
|
||||
delaym( 10 ) ;
|
||||
|
||||
write_register(SETUP_RETR, 5 << ARD | 15 << ARC);
|
||||
write_register(EN_AA, 0b00111111 & ~_BV(BROADCAST_PIPE)) ;
|
||||
write_register(RF_CH, RF24_CHANNEL);
|
||||
write_register(RF_SETUP, (read_register(RF_SETUP) & 0b11010000) | ((RF24_PA_LEVEL << 1) + 1) | ((RF24_DATARATE & 0b00000010 ) << 4) | ((RF24_DATARATE & 0b00000001 ) << 3));
|
||||
write_register(CONFIG, read_register(CONFIG) | _BV(CRCO) | _BV(EN_CRC)) ;
|
||||
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT));
|
||||
|
||||
csnlow();
|
||||
SPItransfer(ACTIVATE);
|
||||
SPItransfer(0x73);
|
||||
csnhigh();
|
||||
write_register(FEATURE, read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) );
|
||||
write_register(DYNPD, read_register(DYNPD) | _BV(DPL_P5) | _BV(DPL_P4) | _BV(DPL_P3) | _BV(DPL_P2) | _BV(DPL_P1) | _BV(DPL_P0));
|
||||
|
||||
spiTrans(FLUSH_RX);
|
||||
spiTrans(FLUSH_TX);
|
||||
|
||||
powerUp(); //Power up by default when begin() is called
|
||||
write_register(CONFIG, read_register(CONFIG) & ~_BV(PRIM_RX));
|
||||
openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS));
|
||||
}
|
||||
#endif // MyOtaBootloaderRF24_H
|
||||
@@ -1,47 +0,0 @@
|
||||
See NodeJsController/Readme.md for usage instructions...
|
||||
|
||||
<h1>Technical details to write your own controller</h1>
|
||||
All initialization the bootloader does (finding parent / requesting nodeId on first start) uses the same packets as a normal MySensors sketch. There is no need for the controller to distinguish between packets from the bootloader and packets from normal sketch execution. The controller only needs to care about two additional request/response communications. All communication is binary.
|
||||
<h2>FirmwareConfig</h2>
|
||||
<ul>
|
||||
<li>the bootloader sends a FirmwareConfigRequest packet to the gateway to request information about the firmware it should execute:
|
||||
<p>
|
||||
typedef struct<br/>
|
||||
{<br/>
|
||||
uint16_t type;<br/>
|
||||
uint16_t version;<br/>
|
||||
} FirmwareConfigRequest;
|
||||
</p>
|
||||
<li>the gateway (the controller) responds with a FirmwareConfigResponse including details about the firmware the sensor should execute:
|
||||
<p>
|
||||
typedef struct<br/>
|
||||
{<br/>
|
||||
uint16_t type;<br/>
|
||||
uint16_t version;<br/>
|
||||
uint16_t blocks;<br/>
|
||||
uint16_t crc;<br/>
|
||||
} FirmwareConfigResponse;
|
||||
</p>
|
||||
</ul>
|
||||
<h2>Firmware</h2>
|
||||
<ul>
|
||||
<li>the bootloader sends a FirmwareRequest packet to the gateway to request a specific subset (block) of the compiled firmware:
|
||||
<p>
|
||||
typedef struct<br/>
|
||||
{<br/>
|
||||
uint16_t type;<br/>
|
||||
uint16_t version;<br/>
|
||||
uint16_t block;<br/>
|
||||
} FirmwareRequest;
|
||||
</p>
|
||||
<li>the gateway (the controller) responds with a FirmwareResponse including the specific block of the compiled firmware:
|
||||
</ul>
|
||||
<p>
|
||||
typedef struct<br/>
|
||||
{<br/>
|
||||
uint16_t type;<br/>
|
||||
uint16_t version;<br/>
|
||||
uint16_t block;<br/>
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE];<br/>
|
||||
} FirmwareResponse;
|
||||
</p>
|
||||
@@ -1,338 +0,0 @@
|
||||
/*
|
||||
MYSBootloader: OTA bootloader for Mysensor nodes (www.mysensors.org)
|
||||
Original OTA bootloader code by ToSa
|
||||
Optimized and extended by tekka
|
||||
Version 1.1 / 20150314
|
||||
Size: 2002 bytes
|
||||
|
||||
Tested with MYSController 0.1.2.276 (goo.gl/9DCWNo)
|
||||
|
||||
MCU: Atmega328p
|
||||
bootsz: 1024W
|
||||
|
||||
fuses for ISP:
|
||||
EX = 0xFE (use 0x06 for Arduino IDE, boards.txt)
|
||||
HI = 0xDA
|
||||
LO = 0xF7
|
||||
|
||||
nRF24L01+ connected to pins:
|
||||
CE = 9
|
||||
CSN = 10
|
||||
|
||||
Successfully tested with:
|
||||
|
||||
16Mhz extXTAL, 3.3V & 5V
|
||||
8Mhz intRC, 3.3V & 5V
|
||||
1Mhz intRC, 3.3 & 5V
|
||||
128kHz intRC, 3.3V & 5V
|
||||
|
||||
* Version 1.1
|
||||
- use eeprom_update instead of eeprom_write to reduce wear out
|
||||
- bootloader commands: erase eeprom, set node id
|
||||
- verify incoming FW blocks for type & address
|
||||
- communicate over static parent (if set and found) else broadcast to find nearest node
|
||||
- adjusted timings
|
||||
|
||||
* Version 1.0
|
||||
Initial release
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "MYSBootloader.h"
|
||||
|
||||
|
||||
#define MYSBOOTLOADER_MAJVER 1
|
||||
#define MYSBOOTLOADER_MINVER 1
|
||||
|
||||
#define MYSBOOTLOADER_VERSION (MYSBOOTLOADER_MINVER * 256 + MYSBOOTLOADER_MAJVER)
|
||||
|
||||
#define MAX_RESEND 5
|
||||
|
||||
|
||||
// procedures and functions
|
||||
|
||||
static void programPage(uint16_t page, uint8_t *buf);
|
||||
static uint16_t calcCRCrom (const void* ptr, uint16_t len);
|
||||
static uint8_t IsFirmwareValid();
|
||||
static void reboot();
|
||||
static void startup();
|
||||
static boolean sendWrite(MyMessage message);
|
||||
static bool sendAndWait(uint8_t reqType, uint8_t resType);
|
||||
|
||||
int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9")));
|
||||
|
||||
|
||||
static void programPage(uint16_t page, uint8_t *buf) {
|
||||
// these function calls use "out" commands: save some bytes and cycles :)
|
||||
__boot_page_erase_short(page);
|
||||
boot_spm_busy_wait();
|
||||
for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) {
|
||||
uint16_t data_word = *buf++;
|
||||
data_word += (*buf++) << 8;
|
||||
__boot_page_fill_short(page + i, data_word);
|
||||
}
|
||||
__boot_page_write_short(page);
|
||||
boot_spm_busy_wait();
|
||||
__boot_rww_enable_short();
|
||||
}
|
||||
|
||||
|
||||
static uint16_t calcCRCrom (const void* ptr, uint16_t len) {
|
||||
// init 0xFFFF
|
||||
uint16_t crc = ~0;
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
crc = _crc16_update(crc, pgm_read_byte((uint16_t) ptr + i));
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t IsFirmwareValid () {
|
||||
return calcCRCrom(0, fc.blocks * FIRMWARE_BLOCK_SIZE) == fc.crc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void reboot() {
|
||||
// wait for pending eeprom activities
|
||||
eeprom_busy_wait();
|
||||
// trigger watchdog ASAP
|
||||
watchdogConfig(WATCHDOG_16MS);
|
||||
// endless loop
|
||||
while (1);
|
||||
}
|
||||
|
||||
static void startup() {
|
||||
if (IsFirmwareValid()) {
|
||||
// WD off
|
||||
watchdogConfig(WATCHDOG_OFF);
|
||||
// run sketch
|
||||
((void(*)()) 0)();
|
||||
|
||||
} else {
|
||||
reboot();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static boolean sendWrite(MyMessage message) {
|
||||
return write(nc.parentNodeId, message.array, HEADER_SIZE + mGetLength(message), (message.destination == BROADCAST_ADDRESS));
|
||||
}
|
||||
|
||||
static bool sendAndWait(uint8_t reqType, uint8_t resType) {
|
||||
outMsg.type = reqType;
|
||||
// outer loop, retries
|
||||
for (uint8_t i = 0; i < MAX_RESEND; i++) {
|
||||
sendWrite(outMsg);
|
||||
// loop 20 times, wait time 0.1s if no/wrong data => 2s
|
||||
for (uint8_t j = 0; j < 20; j++) {
|
||||
// loop 100 times, wait 1ms if no/wrong data => 0.1s
|
||||
for (uint8_t k = 0; k < 100; k++) {
|
||||
watchdogReset();
|
||||
// Tx FIFO data available? (we don't care about the pipe here)
|
||||
if (available(NULL)) {
|
||||
// read message from FIFO, skip if size = 0
|
||||
if (readMessage(inMsg.array) > 0) {
|
||||
// protocol compatible? if not ignore msg
|
||||
if ((mGetVersion(inMsg) != PROTOCOL_VERSION)) {
|
||||
continue;
|
||||
}
|
||||
// msg for us?
|
||||
if (inMsg.destination == nc.nodeId) {
|
||||
// internal command: find parent
|
||||
if ((mGetCommand(inMsg) == C_INTERNAL) && (inMsg.type == I_FIND_PARENT_RESPONSE)) {
|
||||
// static parent found?
|
||||
if (configuredParentID == inMsg.sender) {
|
||||
configuredParentFound = true;
|
||||
}
|
||||
if ( ((inMsg.bValue < nc.distance - 1) && ( !configuredParentFound) ) || (configuredParentID == inMsg.sender)) {
|
||||
// got new routing info, update settings
|
||||
nc.distance = inMsg.bValue + 1;
|
||||
nc.parentNodeId = inMsg.sender;
|
||||
}
|
||||
}
|
||||
// did we receive expected reply?
|
||||
if ((mGetCommand(inMsg) == mGetCommand(outMsg)) && (inMsg.type == resType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// wait 1ms if no data available
|
||||
_delay_ms(1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// main start
|
||||
int main(void) {
|
||||
|
||||
asm volatile ("clr __zero_reg__");
|
||||
// reset MCU status register
|
||||
MCUSR = 0;
|
||||
|
||||
// enable watchdog to avoid deadlock
|
||||
watchdogConfig(WATCHDOG_8S);
|
||||
|
||||
// initialize SPI
|
||||
SPIinit();
|
||||
|
||||
// initialize RF module
|
||||
RFinit();
|
||||
|
||||
// Read node config from EEPROM, i.e. nodeId, parent nodeId, distance
|
||||
eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(struct NodeConfig));
|
||||
// Read firmware config from EEPROM, i.e. type, version, CRC, blocks
|
||||
eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
|
||||
|
||||
// find nearest node during reboot: invalidate parent node settings, since we have to re-discover them for every single reboot
|
||||
configuredParentID = nc.parentNodeId;
|
||||
// nc.parentNodeId = 0xFF;
|
||||
nc.distance = 0xFF;
|
||||
|
||||
// prepare for I_FIND_PARENTS
|
||||
outMsg.sender = nc.nodeId;
|
||||
outMsg.last = nc.nodeId;
|
||||
outMsg.sensor = 0xFF;
|
||||
outMsg.destination = BROADCAST_ADDRESS;
|
||||
|
||||
// set header
|
||||
mSetVersion(outMsg, PROTOCOL_VERSION);
|
||||
mSetLength(outMsg, 0);
|
||||
mSetCommand(outMsg, C_INTERNAL);
|
||||
mSetAck(outMsg,false);
|
||||
mSetPayloadType(outMsg, P_STRING);
|
||||
|
||||
// set reading & writing pipe address
|
||||
setAddress(nc.nodeId);
|
||||
|
||||
// network up? get neighbors, else startup
|
||||
if (!sendAndWait(I_FIND_PARENT, I_FIND_PARENT_RESPONSE)) {
|
||||
startup();
|
||||
}
|
||||
|
||||
// all messages to gateway
|
||||
outMsg.destination = GATEWAY_ADDRESS;
|
||||
|
||||
// if no node id assigned, request new id
|
||||
if (nc.nodeId == AUTO) {
|
||||
// listen to broadcast
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(BROADCAST_ADDRESS));
|
||||
if (sendAndWait(I_ID_REQUEST, I_ID_RESPONSE)) {
|
||||
// save id to eeprom
|
||||
eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, atoi(inMsg.data));
|
||||
}
|
||||
// we could go on and set everything right here, but rebooting will take care of that - and saves some bytes :)
|
||||
reboot();
|
||||
}
|
||||
|
||||
// wuff
|
||||
watchdogReset();
|
||||
// prepare for FW config request
|
||||
RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)outMsg.data;
|
||||
mSetLength(outMsg, sizeof(RequestFirmwareConfig));
|
||||
mSetCommand(outMsg, C_STREAM);
|
||||
mSetPayloadType(outMsg,P_CUSTOM);
|
||||
// copy node settings to reqFWConfig
|
||||
memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig));
|
||||
// add bootloader information
|
||||
reqFWConfig->BLVersion = MYSBOOTLOADER_VERSION;
|
||||
|
||||
// send node config and request FW config from controller
|
||||
if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE)) {
|
||||
startup();
|
||||
}
|
||||
|
||||
NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data;
|
||||
|
||||
// bootloader commands
|
||||
if (firmwareConfigResponse->blocks == 0) {
|
||||
// verify flag
|
||||
if (firmwareConfigResponse->crc == 0xDA7A){
|
||||
// cmd 0x01 clear eeprom
|
||||
if(firmwareConfigResponse->bl_command == 0x01) {
|
||||
for(uint16_t i = 0; i < EEPROM_SIZE; i++) eeprom_update_byte((uint8_t *)i,0xFF);
|
||||
} else
|
||||
// cmd 0x02 set id
|
||||
if(firmwareConfigResponse->bl_command == 0x02) {
|
||||
eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, (uint8_t)firmwareConfigResponse->bl_data);
|
||||
}
|
||||
}
|
||||
// final step
|
||||
reboot();
|
||||
}
|
||||
|
||||
// compare with current node configuration, if equal startup
|
||||
if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
|
||||
startup();
|
||||
}
|
||||
|
||||
// *********** from here on we will fetch new FW
|
||||
|
||||
// invalidate current CRC
|
||||
fc.crc = 0xFFFF;
|
||||
// write fetched type and version in case OTA fails (BL will reboot and re-request FW with stored settings)
|
||||
eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,sizeof(NodeFirmwareConfig));
|
||||
|
||||
// copy new FW config
|
||||
memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
|
||||
RequestFWBlock *firmwareRequest = (RequestFWBlock *)outMsg.data;
|
||||
mSetLength(outMsg, sizeof(RequestFWBlock));
|
||||
|
||||
firmwareRequest->type = fc.type;
|
||||
firmwareRequest->version = fc.version;
|
||||
|
||||
// request FW from controller, load FW counting backwards
|
||||
uint16_t block = fc.blocks;
|
||||
do {
|
||||
firmwareRequest->block = block - 1;
|
||||
|
||||
// request FW block
|
||||
if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE)) {
|
||||
reboot();
|
||||
}
|
||||
|
||||
ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)inMsg.data;
|
||||
|
||||
// did we receive requested block?
|
||||
if (!memcmp(firmwareRequest,firmwareResponse,sizeof(RequestFWBlock))) {
|
||||
// calculate page offset
|
||||
uint8_t offset = ((block - 1) * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE;
|
||||
// write to buffer
|
||||
memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
|
||||
// program if page full
|
||||
if (offset == 0) {
|
||||
programPage(((block - 1) * FIRMWARE_BLOCK_SIZE), progBuf);
|
||||
}
|
||||
block--;
|
||||
}
|
||||
} while (block);
|
||||
|
||||
// wuff
|
||||
watchdogReset();
|
||||
|
||||
// all blocks transmitted, calc CRC and write to eeprom if valid
|
||||
if (IsFirmwareValid()) {
|
||||
// if FW is valid, write settings to eeprom
|
||||
eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
|
||||
}
|
||||
// final step
|
||||
reboot();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#ifndef MyOtaBootloader_H
|
||||
#define MyOtaBootloader_H
|
||||
|
||||
#include <avr/power.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <util/crc16.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "MyMessage.h"
|
||||
#include "MySensor.h"
|
||||
#include "boot.h"
|
||||
#include "MYSBootloaderRF24.h"
|
||||
|
||||
|
||||
#define FIRMWARE_BLOCK_SIZE 16
|
||||
#define EEPROM_SIZE 1024 // 1024 bytes for ATMEGA328
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint16_t type;
|
||||
uint16_t bl_command;
|
||||
};
|
||||
union {
|
||||
uint16_t version;
|
||||
uint16_t bl_data
|
||||
};
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
} __attribute__((packed)) NodeFirmwareConfig;
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t blocks;
|
||||
uint16_t crc;
|
||||
uint16_t BLVersion;
|
||||
} __attribute__((packed)) RequestFirmwareConfig;
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
} __attribute__((packed)) RequestFWBlock;
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t version;
|
||||
uint16_t block;
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE];
|
||||
} __attribute__((packed)) ReplyFWBlock;
|
||||
|
||||
static struct NodeConfig nc;
|
||||
static NodeFirmwareConfig fc;
|
||||
static MyMessage outMsg;
|
||||
static MyMessage inMsg;
|
||||
|
||||
static boolean configuredParentFound = false;
|
||||
static uint8_t configuredParentID = 0xFF;
|
||||
|
||||
//static clock_div_t orgClockDiv = 0;
|
||||
|
||||
static uint8_t progBuf[SPM_PAGESIZE];
|
||||
|
||||
#endif // MyOtaBootloader_H
|
||||
@@ -1,128 +0,0 @@
|
||||
:1078000011E0A0E0B1E0E0EDFFE702C005900D92CD
|
||||
:10781000A230B107D9F721E0A2E0B1E001C01D928A
|
||||
:10782000A83DB207E1F7CDB7DEB76897DEBFCDBFA1
|
||||
:10783000112414BE88E18093600089E28093600087
|
||||
:107840008FEE84B963E083E2D9D16FE584E2D6D1CB
|
||||
:107850006BE381E2D3D16CE485E2D0D167E286E2CA
|
||||
:10786000CDD12ED263E780E5C9D166E08DE3C6D1E4
|
||||
:107870006FE38CE3C3D16EEF80E2C0D18FE19EE471
|
||||
:107880000197F1F700C0000043E050E060E070E0D5
|
||||
:107890008DEC91E06CD348E050E06BE171E085EC59
|
||||
:1078A00091E065D38091CE01809300018FEF8093AA
|
||||
:1078B000CF012091CD012093A5012093A4018093B5
|
||||
:1078C000AA018093A60182E08093A7018091A8017C
|
||||
:1078D000887083608093A8012F3FD1F130E040E0B1
|
||||
:1078E00050E060E070E080E090E034504E41574559
|
||||
:1078F00067457F4F8F4F9F4F29013A014B015C0134
|
||||
:10790000298B5A8A4B8B7C8A6D8B9E8A8F8BB88E83
|
||||
:1079100085E0FE017196A0EDB1E001900D928A958F
|
||||
:10792000E1F745E0BE016F5E7F4F8AE255D149869F
|
||||
:107930005A866B867C868D869E86AF86B88A45E0A1
|
||||
:10794000BE01675F7F4F8BE247D163E082E256D191
|
||||
:1079500068E087E0BAD1811101C09CD11092A601E4
|
||||
:107960008091CD018F3FF1F489838CEF8A8381EE82
|
||||
:107970008B8388EA8C838D831E821F82188645E064
|
||||
:10798000BE016F5F7F4F8BE227D164E083E09DD122
|
||||
:10799000882339F08AE891E0B8D2682F80E090E03F
|
||||
:1079A00005D36FD1A8958091A701877080658093DA
|
||||
:1079B000A7018091A8018871846C8093A80188E058
|
||||
:1079C000E5ECF1E0ABEAB1E001900D928A95E1F7C8
|
||||
:1079D00081E091E09093B4018093B30161E080E095
|
||||
:1079E00074D1811101C056D180918E0190918F0187
|
||||
:1079F000892B09F580919001909191018A379A4DD8
|
||||
:107A000081F680918A0190918B018130910569F412
|
||||
:107A1000A12CB12C6FEFC501C9D2FFEFAF1ABF0A7D
|
||||
:107A2000A11424E0B206B1F7BCCF029709F0B9CF98
|
||||
:107A300060918C01B3CF48E050E06AE871E085ECDA
|
||||
:107A400091E080D2892B09F425D18FEF9FEF90939D
|
||||
:107A5000CC018093CB0148E050E06BE171E085EC14
|
||||
:107A600091E095D288E0EAE8F1E0A5ECB1E0019080
|
||||
:107A70000D928A95E1F78091A701877080638093CA
|
||||
:107A8000A7018091C5019091C6019093AC018093AC
|
||||
:107A9000AB018091C7019091C8019093AE01809392
|
||||
:107AA000AD01A090C901B090CA0110E101E0E5E08C
|
||||
:107AB0007E2EF1E16F2E450181E0881A91089092A7
|
||||
:107AC000B0018092AF0163E082E0FFD0882309F427
|
||||
:107AD00068CF46E050E06AE871E08BEA91E032D28C
|
||||
:107AE000892B09F045C091E0A91A90EFB90A8A2DB7
|
||||
:107AF00082958077A82FB0E0AE5FBE4FE0E9F1E05D
|
||||
:107B0000912F01900D929A95E1F7811130C074E0A8
|
||||
:107B1000AA0CBB1C7A95E1F783E0F50187BFE895D5
|
||||
:107B200007B600FCFDCF4091020180E090E0DC014F
|
||||
:107B3000AE5FBE4FFC01EA0DFB1D11962C91119713
|
||||
:107B400030E0322F2227240F311D090107BFE895AD
|
||||
:107B5000112412964C9102968038910541F7F50157
|
||||
:107B600077BEE89507B600FCFDCF67BEE8955401E7
|
||||
:107B7000A114B10409F09FCFA8954FD0882309F430
|
||||
:107B800010CF48E050E06BE171E085EC91E0FFD16F
|
||||
:107B900008CF98E087FF02C02B9A01C02B982D9A3E
|
||||
:107BA00023B1880F22952170822B2D98915091F747
|
||||
:107BB00008951F93CF93DF93EB01142F2A98E9DFE9
|
||||
:107BC0001C0F1C1721F08FEFE4DF8993FACF2A9A5C
|
||||
:107BD000DF91CF911F9108951F93CF93DF93EB0116
|
||||
:107BE000142F2A98D6DF1C0F1C1719F08991D1DFAA
|
||||
:107BF000FBCF2A9ADF91CF911F910895CF93DF9306
|
||||
:107C00001F92CDB7DEB7698341E0BE016F5F7F4F42
|
||||
:107C1000E3DF0F90DF91CF9108958091C90190919A
|
||||
:107C2000CA0124E0880F991F2A95E1F7E0E0F0E00F
|
||||
:107C30002FEF3FEFE817F907D1F044912427422FA7
|
||||
:107C400042954227042E469546954025042E46959A
|
||||
:107C500040254770022E232F469507944795302DD7
|
||||
:107C6000242706944795302524273196E3CF81E0D9
|
||||
:107C70004091CB015091CC012417350709F080E0E9
|
||||
:107C80000895F999FECF88E18093600088E08093A1
|
||||
:107C90006000FFCFC2DF882341F088E1809360005D
|
||||
:107CA00010926000E0E0F0E00994EBDF40E060E07B
|
||||
:107CB00070E082EE91CF40E060E070E081EE8CCF2A
|
||||
:107CC000F5DFF9DF60E787E299CF6F927F928F92BD
|
||||
:107CD0009F92AF92BF92CF92DF92EF92FF920F935B
|
||||
:107CE0001F93CF93DF93CDB7DEB7AA97DEBFCDBF8B
|
||||
:107CF000762E8093A90105E051E2652EE4EAF1E0D9
|
||||
:107D0000DE011196862D01900D928A95E1F7FB8098
|
||||
:107D10001C81169516951695195F2091CE0129980C
|
||||
:107D20002AA7CEDF6EEF80E269DF2AA530E040E0CF
|
||||
:107D300050E060E070E080E090E034504E41574504
|
||||
:107D400067457F4F8F4F9F4F2AA33BA34CA35DA353
|
||||
:107D50006EA37FA388A799A745E0BE016E5D7F4F04
|
||||
:107D60008AE23ADF45E0BE016E5D7F4F80E334DF9B
|
||||
:107D70008FEFF81202C080EB01C080EA412FBE01F4
|
||||
:107D80006F5F7F4F29DF299A9AE69A95F1F700C035
|
||||
:107D9000299840E060E070E08FEF0BDF8073C9F35B
|
||||
:107DA00060E787E22BDF84FD86DF6FE080E226DF7D
|
||||
:107DB00087DF8090D0019090D101A090D201B09047
|
||||
:107DC000D301C090D401D090D501E090D601F090BD
|
||||
:107DD000D7019401A501B601C701A0E08AD029F01E
|
||||
:107DE00045E060ED71E08AE2F7DE299A44E1E42E95
|
||||
:107DF00034E6F32EA89541E060E070E087E1D9DE3B
|
||||
:107E000080FD5EC041E060E070E080E6D2DE182FC9
|
||||
:107E1000813210F04BDF10E0412F63E871E081E622
|
||||
:107E2000C8DE60E787E2EADE1123E9F1809186018E
|
||||
:107E300087708230C1F5909185018091CD019813B2
|
||||
:107E400032C050918701852F8770833019F580915A
|
||||
:107E500088018830F9F47091000140918401741315
|
||||
:107E600003C081E08093820160918A01262F30E077
|
||||
:107E70008091CF0190E001972817390724F4809171
|
||||
:107E80008201882311F0741305C06F5F6093CF01E6
|
||||
:107E90004093CE018091A8018527877021F48091BD
|
||||
:107EA0008801871559F0FA9409F0A4CFEA9409F0F3
|
||||
:107EB0009FCF015009F022CF80E009C081E007C0C8
|
||||
:107EC0008FE99FE00197F1F700C00000ECCFAA9680
|
||||
:107ED000DEBFCDBFDF91CF911F910F91FF90EF904B
|
||||
:107EE000DF90CF90BF90AF909F908F907F906F90DA
|
||||
:107EF00008950024A7FD00942A1730054005500579
|
||||
:107F000060057005800590050895FC018827992774
|
||||
:107F1000E89421912032E9F3293010F02E30C8F393
|
||||
:107F20002B3239F02D3231F4689403C018D0820F0F
|
||||
:107F3000911D219120532A30C8F31EF4909581950C
|
||||
:107F40009F4F0895FB01DC0104C08D9101908019C1
|
||||
:107F500021F441505040C8F7881B990B08957AE0EE
|
||||
:107F6000979F902D879F802D910D11240895DC01FE
|
||||
:107F7000CB01FC01F999FECF06C0F2BDE1BDF89A34
|
||||
:107F8000319600B40D9241505040B8F70895DC018D
|
||||
:107F9000A40FB51F4150504040F0CB01840F951FF6
|
||||
:107FA0002E9105D041505040D8F70895262FF999C9
|
||||
:107FB000FECF92BD81BDF89A019700B4021639F048
|
||||
:107FC0001FBA20BD0FB6F894FA9AF99A0FBE089519
|
||||
:027FD000FF00B0
|
||||
:040000030000780081
|
||||
:00000001FF
|
||||
@@ -1,128 +0,0 @@
|
||||
#ifndef MYSBootloaderHW_H
|
||||
#define MYSBootloaderHW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// hardware
|
||||
|
||||
#define F_CPU_DIV clock_div_4
|
||||
#define F_CPU_REAL F_CPU / (F_CPU_DIV)
|
||||
#define BAUD_SETTING (( (F_CPU_REAL + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 )
|
||||
#define BAUD_ACTUAL (F_CPU_REAL/(8 * ((BAUD_SETTING)+1)))
|
||||
#define BAUD_ERROR (( 100*(BAUD_RATE - BAUD_ACTUAL) ) / BAUD_RATE)
|
||||
#define UART_SRA UCSR0A
|
||||
#define UART_SRB UCSR0B
|
||||
#define UART_SRC UCSR0C
|
||||
#define UART_SRL UBRR0L
|
||||
#define UART_UDR UDR0
|
||||
|
||||
// boolean definition
|
||||
|
||||
typedef uint8_t bool;
|
||||
typedef uint8_t boolean;
|
||||
#define false 0x0
|
||||
#define true 0x1
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
|
||||
// Watchdog definitions and functions
|
||||
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||
|
||||
inline void watchdogReset() {
|
||||
asm volatile ("wdr");
|
||||
}
|
||||
|
||||
void watchdogConfig(uint8_t x) {
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = x;
|
||||
}
|
||||
|
||||
// SPI communication
|
||||
|
||||
#define SPI_DDR DDRB
|
||||
#define SPI_PORT PORTB
|
||||
#define SPI_PIN PINB
|
||||
#define SPI_SCLK 5 // Arduino Pin 13 <-> Bit 5 of port B
|
||||
#define SPI_MISO 4 // Arduino Pin 12 <-> Bit 4 of port B
|
||||
#define SPI_MOSI 3 // Arduino Pin 11 <-> Bit 3 of port B
|
||||
#define SPI_CSN 2 // Arduino Pin 10 <-> Bit 2 of port B
|
||||
#define SPI_CE 1 // Arduino Pin 9 <-> Bit 1 of port B
|
||||
#define CE_PULSE_LENGTH 20 // IMPORTANT: minimum CE pulse width 10us, see nRF24L01 specs. Set 20us to be on the safe side
|
||||
|
||||
#define csnlow() SPI_PORT &= ~_BV(SPI_CSN)
|
||||
#define csnhigh() SPI_PORT |= _BV(SPI_CSN)
|
||||
#define celow() SPI_PORT &= ~_BV(SPI_CE)
|
||||
#define cehigh() SPI_PORT |= _BV(SPI_CE)
|
||||
|
||||
static void SPIinit() {
|
||||
// set pin mode: MOSI,SCLK,CE = OUTPUT, MISO = INPUT
|
||||
SPI_DDR = _BV(SPI_MOSI) | _BV(SPI_SCLK) | _BV(SPI_CE) | _BV(SPI_CSN) | ~_BV(SPI_MISO);
|
||||
}
|
||||
|
||||
static uint8_t SPItransfer(uint8_t value) {
|
||||
// bit bang SPI
|
||||
for(uint8_t i = 0; i<8; i++) {
|
||||
if (value & 0x80) SPI_PORT |= _BV(SPI_MOSI); else SPI_PORT &= ~_BV(SPI_MOSI);
|
||||
//_delay_us(1);
|
||||
value <<= 1;
|
||||
SPI_PORT |= _BV(SPI_SCLK);
|
||||
//_delay_us(1);
|
||||
value |= ((SPI_PIN >> SPI_MISO) & 0x01);
|
||||
SPI_PORT &= ~_BV(SPI_SCLK);
|
||||
//_delay_us(1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// UART debug
|
||||
|
||||
static void uart_init() {
|
||||
//Double speed mode USART0
|
||||
UART_SRA = _BV(U2X0);
|
||||
UART_SRB = _BV(RXEN0) | _BV(TXEN0);
|
||||
UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
}
|
||||
|
||||
void putch(char ch) {
|
||||
while (!(UART_SRA & _BV(UDRE0)));
|
||||
UART_UDR = ch;
|
||||
}
|
||||
|
||||
uint8_t getch() {
|
||||
uint8_t ch;
|
||||
// wait until char received
|
||||
while(!(UART_SRA & _BV(RXC0)));
|
||||
// framing error?
|
||||
if (!(UART_SRA & _BV(FE0))) {
|
||||
watchdogReset();
|
||||
}
|
||||
ch = UART_UDR;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_string(char *s) {
|
||||
while (*s)
|
||||
putch(*s++);
|
||||
}
|
||||
|
||||
static void put_int(uint8_t i) {
|
||||
char s[5];
|
||||
itoa( i, s, 10 );
|
||||
put_string( s );
|
||||
}
|
||||
|
||||
|
||||
#endif // MYSBootloaderHW_H
|
||||
@@ -1,208 +0,0 @@
|
||||
#ifndef MYSBootloaderRF24_H
|
||||
#define MYSBootloaderRF24_H
|
||||
|
||||
#include "MYSBootloaderHW.h"
|
||||
#include "nRF24L01.h"
|
||||
|
||||
typedef enum { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR } rf24_pa_dbm_e ;
|
||||
typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e;
|
||||
|
||||
#define _write_register(reg) ( (reg) | W_REGISTER)
|
||||
#define _read_register(reg) ( (reg) | R_REGISTER)
|
||||
#define addr_width 5
|
||||
|
||||
uint64_t pipe0_reading_address = 0;
|
||||
|
||||
static uint8_t BurstReadAddress(uint8_t addr, uint8_t* buf, uint8_t len) {
|
||||
csnlow();
|
||||
uint8_t status = SPItransfer( addr );
|
||||
while ( len-- ) {
|
||||
status = SPItransfer(NOP);
|
||||
*buf++ = status;
|
||||
}
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t BurstWriteAddress(uint8_t addr, uint8_t* buf, uint8_t len) {
|
||||
csnlow();
|
||||
uint8_t status = SPItransfer( addr );
|
||||
while ( len-- ) {
|
||||
status = SPItransfer(*buf++);
|
||||
}
|
||||
csnhigh();
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint8_t ReadAddress(uint8_t addr) {
|
||||
return BurstReadAddress(addr,NULL,1);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t WriteAddress(uint8_t addr, uint8_t val) {
|
||||
return BurstWriteAddress(addr,&val,1);
|
||||
}
|
||||
|
||||
#define BurstWriteRegister(reg,buf,len) BurstWriteAddress(_write_register(reg), buf, len)
|
||||
#define WriteRegister(reg,val) WriteAddress(_write_register(reg), val)
|
||||
#define BurstReadRegister(reg,buf,len) BurstReadAddress(_read_register(reg), buf, len)
|
||||
#define ReadRegister(reg) ReadAddress(_read_register(reg))
|
||||
#define get_status() BurstReadAddress(NOP, NULL, 0)
|
||||
|
||||
void Flush_RX(void) {
|
||||
BurstWriteAddress(FLUSH_RX, NULL, 0);
|
||||
}
|
||||
|
||||
void Flush_TX(void) {
|
||||
BurstWriteAddress(FLUSH_TX, NULL, 0);
|
||||
}
|
||||
|
||||
static void Flush_RXTX_CLI(void) {
|
||||
// flush RX and TX buffer
|
||||
Flush_RX();
|
||||
Flush_TX();
|
||||
// clear registers
|
||||
WriteRegister(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
}
|
||||
|
||||
static void startListening(void) {
|
||||
// for size reasons, we do not read back the register content, set PRIM_RX
|
||||
WriteRegister(CONFIG, _BV(PWR_UP) | _BV(CRCO) | _BV(EN_CRC) | _BV(PRIM_RX)) ;
|
||||
Flush_RXTX_CLI();
|
||||
// write pipe0 address
|
||||
if (pipe0_reading_address){
|
||||
BurstWriteRegister(RX_ADDR_P0, (uint8_t*)&pipe0_reading_address, addr_width);
|
||||
}
|
||||
cehigh();
|
||||
}
|
||||
|
||||
static void stopListening(void) {
|
||||
celow();
|
||||
Flush_RXTX_CLI();
|
||||
// for size reasons, we do not read back the register content, clear PRIM_RX
|
||||
WriteRegister(CONFIG, _BV(PWR_UP) | _BV(CRCO) | _BV(EN_CRC) | ~_BV(PRIM_RX)) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static boolean write_buf(uint8_t* buf, uint8_t len, const bool multicast ) {
|
||||
// write payload to FIFO
|
||||
BurstWriteRegister( multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, buf, len) ;
|
||||
// CE pulse to start transmission
|
||||
cehigh();
|
||||
// IMPORTANT: minimum CE pulse width 10us, see nRF24L01 specs
|
||||
_delay_us(CE_PULSE_LENGTH);
|
||||
// start transmitting
|
||||
celow();
|
||||
|
||||
|
||||
// wait until sent or ACKed, here we potentially have a deadlock when transmitter not connected/not working => wdt recovers
|
||||
while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { }
|
||||
// read interrupts and clear
|
||||
uint8_t status = WriteRegister(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
// max retries? clear FIFO
|
||||
if( status & _BV(MAX_RT)){
|
||||
Flush_TX();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t getDynamicPayloadSize(void) {
|
||||
uint8_t result = ReadAddress(R_RX_PL_WID);
|
||||
if(result > 32) {
|
||||
Flush_RX();
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static boolean available(uint8_t* pipe_num) {
|
||||
if (!(ReadAddress(FIFO_STATUS) & _BV(RX_EMPTY) )){
|
||||
if (pipe_num) {
|
||||
uint8_t status = get_status();
|
||||
*pipe_num = ( status >> RX_P_NO ) & 0b111;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t readMessage(uint8_t* buf) {
|
||||
// read payload
|
||||
uint8_t PL_LEN = getDynamicPayloadSize();
|
||||
BurstReadRegister(R_RX_PAYLOAD,buf,PL_LEN);
|
||||
// reset interrupts
|
||||
WriteRegister(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
return PL_LEN;
|
||||
}
|
||||
|
||||
static void openWritingPipe(uint64_t value) {
|
||||
BurstWriteRegister(RX_ADDR_P0, (uint8_t*)&value, addr_width);
|
||||
BurstWriteRegister(TX_ADDR, (uint8_t*)&value, addr_width);
|
||||
}
|
||||
|
||||
static void openReadingPipe(uint8_t pipe, uint64_t address) {
|
||||
// If this is pipe 0, cache the address. This is needed because openWritingPipe() will overwrite the pipe 0 address, so
|
||||
// startListening() will have to restore it
|
||||
if (pipe == WRITE_PIPE) {
|
||||
memcpy(&pipe0_reading_address,&address,addr_width);
|
||||
}
|
||||
// only write full address for pipe 0 and 1
|
||||
// since we do not use the BROADCASTING PIPE in this bootloader, we can remove the check
|
||||
//if ( pipe < 2 )
|
||||
{
|
||||
BurstWriteRegister(RX_ADDR_P0 + pipe, (uint8_t*)&address, addr_width);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static boolean write(uint8_t destination, uint8_t* buf, uint8_t len, boolean multicast) {
|
||||
stopListening();
|
||||
openWritingPipe(TO_ADDR(destination));
|
||||
boolean result = write_buf(buf, len, multicast);
|
||||
startListening();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void setAddress(uint8_t addr)
|
||||
{
|
||||
if (addr != BROADCAST_ADDRESS) {
|
||||
openReadingPipe(WRITE_PIPE, TO_ADDR(addr));
|
||||
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(addr));
|
||||
// enable pipe
|
||||
WriteRegister(EN_RXADDR,_BV(ERX_P0 + WRITE_PIPE) | _BV(ERX_P0 + CURRENT_NODE_PIPE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void RFinit(void){
|
||||
// set address width
|
||||
WriteRegister(SETUP_AW, (addr_width-2) % 4);
|
||||
// auto retransmit delay 1500us, auto retransmit count 15
|
||||
WriteRegister(SETUP_RETR, 5 << ARD | 15 << ARC);
|
||||
// enable auto ack on all pipes, except broadcasting pipe
|
||||
WriteRegister(EN_AA, 0b00111111 & ~_BV(BROADCAST_PIPE)) ;
|
||||
// set channel
|
||||
WriteRegister(RF_CH, RF24_CHANNEL);
|
||||
// set data rate
|
||||
WriteRegister(RF_SETUP, ((RF24_DATARATE & 0b00000010 ) << 4) | ((RF24_DATARATE & 0b00000001 ) << 3) | ((RF24_PA_LEVEL << 1) + 1));
|
||||
// flush RX and TX FIFO, clear interrupts
|
||||
Flush_RXTX_CLI();
|
||||
// activate to unlock features
|
||||
WriteAddress(ACTIVATE,0x73);
|
||||
// enable payload with ACK and dynamic payload length
|
||||
WriteRegister(FEATURE, _BV(EN_ACK_PAY) | _BV(EN_DPL) );
|
||||
// Enable dynamic payload length on all pipes
|
||||
WriteRegister(DYNPD, _BV(DPL_P5) | _BV(DPL_P4) | _BV(DPL_P3) | _BV(DPL_P2) | _BV(DPL_P1) | _BV(DPL_P0));
|
||||
//powerUp, enable 16bit CRC, no RX mode
|
||||
WriteRegister(CONFIG, _BV(PWR_UP) | _BV(CRCO) | _BV(EN_CRC) | ~_BV(PRIM_RX));
|
||||
// stabilize 5ms
|
||||
_delay_ms(5);
|
||||
}
|
||||
|
||||
#endif // MYSBootloaderRF24_H
|
||||
@@ -1,65 +0,0 @@
|
||||
PROJECT = MYSBootloader
|
||||
INCLUDES = ../libraries/MySensors
|
||||
|
||||
MCU = atmega328p
|
||||
CLK = 16000000L
|
||||
|
||||
ISP_PORT = com5
|
||||
ISP_SPEED = 115200
|
||||
ISP_PROTOCOL = stk500v2
|
||||
ISP_MCU = m328p
|
||||
ISP_HFUSE = DA
|
||||
ISP_LFUSE = F7
|
||||
ISP_EFUSE = 06
|
||||
ISP_ARGS = -c$(ISP_PROTOCOL) -P$(ISP_PORT) -b$(ISP_SPEED) -p$(ISP_MCU)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
BINPATH = C:/Program Files (x86)/Arduino/hardware/tools/avr/bin/
|
||||
JAVAPATH = C:/Program Files/Java/jdk1.7.0_40/bin/
|
||||
JAVAC = $(JAVAPATH)javac.exe
|
||||
JAVA = $(JAVAPATH)java.exe
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
UNAME_P := $(shell uname -p)
|
||||
UNAME_M := $(shell uname -m)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
BINPATH = ../arduino/bin-linux64/bin/
|
||||
else ifneq ($(filter %86,$(UNAME_P)),)
|
||||
BINPATH = ../arduino/bin-linux32/bin/
|
||||
else ifneq ($(filter arm%,$(UNAME_M)),)
|
||||
BINPATH = /usr/bin/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS = -x c -mno-interrupts -funsigned-char -funsigned-bitfields -DF_CPU=$(CLK)-Os -fno-inline-small-functions -fno-split-wide-types -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mrelax -Wall -mmcu=$(MCU) -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"
|
||||
LDFLAGS = -nostartfiles -Wl,-s -Wl,-static -Wl,-Map="$(OutputFileName).map" -Wl,--start-group -Wl,--end-group -Wl,--gc-sections -mrelax -Wl,-section-start=.text=0x7800 -mmcu=$(MCU)
|
||||
|
||||
|
||||
|
||||
all: clean out
|
||||
|
||||
clean:
|
||||
- rm *.o
|
||||
- rm *.elf
|
||||
- rm *.hex
|
||||
|
||||
$(PROJECT).o: $(PROJECT).c
|
||||
"$(BINPATH)avr-gcc" $(CFLAGS) -I$(INCLUDES) $< -o $@
|
||||
|
||||
$(PROJECT).elf: $(PROJECT).o
|
||||
"$(BINPATH)avr-gcc" $(LDFLAGS) -o $@ $< -lm
|
||||
|
||||
$(PROJECT).hex: $(PROJECT).elf
|
||||
"$(BINPATH)avr-objcopy" -O ihex -R .eeprom $< $@
|
||||
|
||||
out: $(PROJECT).hex
|
||||
"$(BINPATH)avr-size" $(PROJECT).elf
|
||||
|
||||
load: clean out isp
|
||||
|
||||
isp: $(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -e -u -Ulock:w:0x3f:m -qq -Uefuse:w:0x$(ISP_EFUSE):m -Uhfuse:w:0x$(ISP_HFUSE):m -Ulfuse:w:0x$(ISP_LFUSE):m -Ulock:w:0x0f:m
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS) -V -q -s -Uflash:w:$(PROJECT).hex
|
||||
"$(BINPATH)avrdude" $(ISP_ARGS)
|
||||
@@ -1,62 +0,0 @@
|
||||
# See: http://code.google.com/p/arduino/wiki/Platforms
|
||||
|
||||
menu.cpu=Processor
|
||||
|
||||
uno.name=Arduino Uno Optiboot
|
||||
|
||||
uno.vid.0=0x2341
|
||||
uno.pid.0=0x0043
|
||||
uno.vid.1=0x2341
|
||||
uno.pid.1=0x0001
|
||||
|
||||
uno.upload.tool=avrdude
|
||||
uno.upload.protocol=arduino
|
||||
uno.upload.maximum_size=32256
|
||||
uno.upload.maximum_data_size=2048
|
||||
uno.upload.speed=115200
|
||||
|
||||
uno.bootloader.tool=avrdude
|
||||
uno.bootloader.low_fuses=0xFF
|
||||
uno.bootloader.high_fuses=0xDE
|
||||
uno.bootloader.extended_fuses=0x05
|
||||
uno.bootloader.unlock_bits=0x3F
|
||||
uno.bootloader.lock_bits=0x0F
|
||||
uno.bootloader.file=optiboot/optiboot_atmega328.hex
|
||||
|
||||
uno.build.mcu=atmega328p
|
||||
uno.build.f_cpu=16000000L
|
||||
uno.build.board=AVR_UNO
|
||||
uno.build.core=arduino
|
||||
uno.build.variant=standard
|
||||
|
||||
|
||||
## Arduino Pro or Pro Mini (3V3 & 5V, 16 MHz) w/ ATmega328 MYSBootloader
|
||||
## -------------------------------------------------
|
||||
|
||||
|
||||
proMYSBL.name=ATmega328 16Mhz MYSBootloader
|
||||
|
||||
proMYSBL.upload.tool=avrdude
|
||||
proMYSBL.upload.protocol=arduino
|
||||
proMYSBL.upload.maximum_size=30720
|
||||
proMYSBL.upload.maximum_data_size=2048
|
||||
proMYSBL.upload.speed=115200
|
||||
|
||||
proMYSBL.bootloader.tool=avrdude
|
||||
proMYSBL.bootloader.low_fuses=0xF7
|
||||
proMYSBL.bootloader.high_fuses=0xDA
|
||||
proMYSBL.bootloader.extended_fuses=0x06
|
||||
proMYSBL.bootloader.unlock_bits=0x3F
|
||||
proMYSBL.bootloader.lock_bits=0x0F
|
||||
proMYSBL.bootloader.file=MySensors/MYSBootloader.hex
|
||||
|
||||
proMYSBL.build.mcu=atmega328p
|
||||
proMYSBL.build.f_cpu=16000000L
|
||||
proMYSBL.build.board=AVR_UNO
|
||||
proMYSBL.build.core=arduino
|
||||
proMYSBL.build.variant=standard
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,848 +0,0 @@
|
||||
/* Modified to use out for SPM access
|
||||
** Peter Knight, Optiboot project http://optiboot.googlecode.com
|
||||
**
|
||||
** Todo: Tidy up
|
||||
**
|
||||
** "_short" routines execute 1 cycle faster and use 1 less word of flash
|
||||
** by using "out" instruction instead of "sts".
|
||||
**
|
||||
** Additional elpm variants that trust the value of RAMPZ
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
|
||||
|
||||
#ifndef _AVR_BOOT_H_
|
||||
#define _AVR_BOOT_H_ 1
|
||||
|
||||
/** \file */
|
||||
/** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities
|
||||
\code
|
||||
#include <avr/io.h>
|
||||
#include <avr/boot.h>
|
||||
\endcode
|
||||
|
||||
The macros in this module provide a C language interface to the
|
||||
bootloader support functionality of certain AVR processors. These
|
||||
macros are designed to work with all sizes of flash memory.
|
||||
|
||||
Global interrupts are not automatically disabled for these macros. It
|
||||
is left up to the programmer to do this. See the code example below.
|
||||
Also see the processor datasheet for caveats on having global interrupts
|
||||
enabled during writing of the Flash.
|
||||
|
||||
\note Not all AVR processors provide bootloader support. See your
|
||||
processor datasheet to see if it provides bootloader support.
|
||||
|
||||
\todo From email with Marek: On smaller devices (all except ATmega64/128),
|
||||
__SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
|
||||
instructions - since the boot loader has a limited size, this could be an
|
||||
important optimization.
|
||||
|
||||
\par API Usage Example
|
||||
The following code shows typical usage of the boot API.
|
||||
|
||||
\code
|
||||
#include <inttypes.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
void boot_program_page (uint32_t page, uint8_t *buf)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t sreg;
|
||||
|
||||
// Disable interrupts.
|
||||
|
||||
sreg = SREG;
|
||||
cli();
|
||||
|
||||
eeprom_busy_wait ();
|
||||
|
||||
boot_page_erase (page);
|
||||
boot_spm_busy_wait (); // Wait until the memory is erased.
|
||||
|
||||
for (i=0; i<SPM_PAGESIZE; i+=2)
|
||||
{
|
||||
// Set up little-endian word.
|
||||
|
||||
uint16_t w = *buf++;
|
||||
w += (*buf++) << 8;
|
||||
|
||||
boot_page_fill (page + i, w);
|
||||
}
|
||||
|
||||
boot_page_write (page); // Store buffer in flash page.
|
||||
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||
|
||||
// Reenable RWW-section again. We need this if we want to jump back
|
||||
// to the application after bootloading.
|
||||
|
||||
boot_rww_enable ();
|
||||
|
||||
// Re-enable interrupts (if they were ever enabled).
|
||||
|
||||
SREG = sreg;
|
||||
}\endcode */
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Check for SPM Control Register in processor. */
|
||||
#if defined (SPMCSR)
|
||||
# define __SPM_REG SPMCSR
|
||||
#elif defined (SPMCR)
|
||||
# define __SPM_REG SPMCR
|
||||
#else
|
||||
# error AVR processor does not provide bootloader support!
|
||||
#endif
|
||||
|
||||
|
||||
/* Check for SPM Enable bit. */
|
||||
#if defined(SPMEN)
|
||||
# define __SPM_ENABLE SPMEN
|
||||
#elif defined(SELFPRGEN)
|
||||
# define __SPM_ENABLE SELFPRGEN
|
||||
#else
|
||||
# error Cannot find SPM Enable bit definition!
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def BOOTLOADER_SECTION
|
||||
|
||||
Used to declare a function or variable to be placed into a
|
||||
new section called .bootloader. This section and its contents
|
||||
can then be relocated to any address (such as the bootloader
|
||||
NRWW area) at link-time. */
|
||||
|
||||
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
|
||||
|
||||
/* Create common bit definitions. */
|
||||
#ifdef ASB
|
||||
#define __COMMON_ASB ASB
|
||||
#else
|
||||
#define __COMMON_ASB RWWSB
|
||||
#endif
|
||||
|
||||
#ifdef ASRE
|
||||
#define __COMMON_ASRE ASRE
|
||||
#else
|
||||
#define __COMMON_ASRE RWWSRE
|
||||
#endif
|
||||
|
||||
/* Define the bit positions of the Boot Lock Bits. */
|
||||
|
||||
#define BLB12 5
|
||||
#define BLB11 4
|
||||
#define BLB02 3
|
||||
#define BLB01 2
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_enable()
|
||||
Enable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_interrupt_disable()
|
||||
Disable the SPM interrupt. */
|
||||
|
||||
#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_is_spm_interrupt()
|
||||
Check if the SPM interrupt is enabled. */
|
||||
|
||||
#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_busy()
|
||||
Check if the RWW section is busy. */
|
||||
|
||||
#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy()
|
||||
Check if the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_spm_busy_wait()
|
||||
Wait while the SPM instruction is busy. */
|
||||
|
||||
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
|
||||
|
||||
#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
|
||||
#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
|
||||
#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
|
||||
#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
|
||||
#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
|
||||
|
||||
#define __boot_page_fill_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_normal(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_alternate(address, data)\
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %3\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"z" ((uint16_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_fill_extended_short(address, data) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r0, %4\n\t" \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
"clr r1\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||
"r" ((uint32_t)address), \
|
||||
"r" ((uint16_t)data) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
|
||||
#define __boot_page_erase_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_erase_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_erase_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_normal(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_alternate(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"z" ((uint16_t)address) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_page_write_extended(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"sts %1, %C3\n\t" \
|
||||
"sts %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
#define __boot_page_write_extended_short(address) \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"movw r30, %A3\n\t" \
|
||||
"out %1, %C3\n\t" \
|
||||
"out %0, %2\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||
"r" ((uint32_t)address) \
|
||||
: "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_short() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_rww_enable_alternate() \
|
||||
(__extension__({ \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||
); \
|
||||
}))
|
||||
|
||||
/* From the mega16/mega128 data sheets (maybe others):
|
||||
|
||||
Bits by SPM To set the Boot Loader Lock bits, write the desired data to
|
||||
R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
|
||||
after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
|
||||
that may prevent the Application and Boot Loader section from any
|
||||
software update by the MCU.
|
||||
|
||||
If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
|
||||
will be programmed if an SPM instruction is executed within four cycles
|
||||
after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
|
||||
don't care during this operation, but for future compatibility it is
|
||||
recommended to load the Z-pointer with $0001 (same as used for reading the
|
||||
Lock bits). For future compatibility It is also recommended to set bits 7,
|
||||
6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
|
||||
Lock bits the entire Flash can be read during the operation. */
|
||||
|
||||
#define __boot_lock_bits_set_short(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"out %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
#define __boot_lock_bits_set_alternate(lock_bits) \
|
||||
(__extension__({ \
|
||||
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, 1\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"mov r0, %2\n\t" \
|
||||
"sts %0, %1\n\t" \
|
||||
"spm\n\t" \
|
||||
".word 0xffff\n\t" \
|
||||
"nop\n\t" \
|
||||
: \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"r" (value) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
}))
|
||||
|
||||
/*
|
||||
Reading lock and fuse bits:
|
||||
|
||||
Similarly to writing the lock bits above, set BLBSET and SPMEN (or
|
||||
SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
|
||||
LPM instruction.
|
||||
|
||||
Z address: contents:
|
||||
0x0000 low fuse bits
|
||||
0x0001 lock bits
|
||||
0x0002 extended fuse bits
|
||||
0x0003 high fuse bits
|
||||
|
||||
Sounds confusing, doesn't it?
|
||||
|
||||
Unlike the macros in pgmspace.h, no need to care for non-enhanced
|
||||
cores here as these old cores do not provide SPM support anyway.
|
||||
*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOW_FUSE_BITS
|
||||
address to read the low fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOW_FUSE_BITS (0x0000)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_LOCK_BITS
|
||||
address to read the lock bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_LOCK_BITS (0x0001)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_EXTENDED_FUSE_BITS
|
||||
address to read the extended fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_EXTENDED_FUSE_BITS (0x0002)
|
||||
/** \ingroup avr_boot
|
||||
\def GET_HIGH_FUSE_BITS
|
||||
address to read the high fuse bits, using boot_lock_fuse_bits_get
|
||||
*/
|
||||
#define GET_HIGH_FUSE_BITS (0x0003)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_fuse_bits_get(address)
|
||||
|
||||
Read the lock or fuse bits at \c address.
|
||||
|
||||
Parameter \c address can be any of GET_LOW_FUSE_BITS,
|
||||
GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
|
||||
|
||||
\note The lock and fuse bits returned are the physical values,
|
||||
i.e. a bit returned as 0 means the corresponding fuse or lock bit
|
||||
is programmed.
|
||||
*/
|
||||
#define boot_lock_fuse_bits_get_short(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_lock_fuse_bits_get(address) \
|
||||
(__extension__({ \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"ldi r30, %3\n\t" \
|
||||
"ldi r31, 0\n\t" \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||
"M" (address) \
|
||||
: "r0", "r30", "r31" \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_signature_byte_get(address)
|
||||
|
||||
Read the Signature Row byte at \c address. For some MCU types,
|
||||
this function can also retrieve the factory-stored oscillator
|
||||
calibration bytes.
|
||||
|
||||
Parameter \c address can be 0-0x1f as documented by the datasheet.
|
||||
\note The values are MCU type dependent.
|
||||
*/
|
||||
|
||||
#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
|
||||
|
||||
#define boot_signature_byte_get_short(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"out %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
#define boot_signature_byte_get(addr) \
|
||||
(__extension__({ \
|
||||
uint16_t __addr16 = (uint16_t)(addr); \
|
||||
uint8_t __result; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"sts %1, %2\n\t" \
|
||||
"lpm %0, Z" "\n\t" \
|
||||
: "=r" (__result) \
|
||||
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||
"z" (__addr16) \
|
||||
); \
|
||||
__result; \
|
||||
}))
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_fill(address, data)
|
||||
|
||||
Fill the bootloader temporary page buffer for flash
|
||||
address with data word.
|
||||
|
||||
\note The address is a byte address. The data is a word. The AVR
|
||||
writes data to the buffer a word at a time, but addresses the buffer
|
||||
per byte! So, increment your address by 2 between calls, and send 2
|
||||
data bytes in a word format! The LSB of the data is written to the lower
|
||||
address; the MSB of the data is written to the higher address.*/
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_erase(address)
|
||||
|
||||
Erase the flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_page_write(address)
|
||||
|
||||
Write the bootloader temporary page buffer
|
||||
to flash page that contains address.
|
||||
|
||||
\note address is a byte address in flash, not a word address. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_rww_enable()
|
||||
|
||||
Enable the Read-While-Write memory section. */
|
||||
|
||||
/** \ingroup avr_boot
|
||||
\def boot_lock_bits_set(lock_bits)
|
||||
|
||||
Set the bootloader lock bits.
|
||||
|
||||
\param lock_bits A mask of which Boot Loader Lock Bits to set.
|
||||
|
||||
\note In this context, a 'set bit' will be written to a zero value.
|
||||
Note also that only BLBxx bits can be programmed by this command.
|
||||
|
||||
For example, to disallow the SPM instruction from writing to the Boot
|
||||
Loader memory section of flash, you would use this macro as such:
|
||||
|
||||
\code
|
||||
boot_lock_bits_set (_BV (BLB11));
|
||||
\endcode
|
||||
|
||||
\note Like any lock bits, the Boot Loader Lock Bits, once set,
|
||||
cannot be cleared again except by a chip erase which will in turn
|
||||
also erase the boot loader itself. */
|
||||
|
||||
/* Normal versions of the macros use 16-bit addresses.
|
||||
Extended versions of the macros use 32-bit addresses.
|
||||
Alternate versions of the macros use 16-bit addresses and require special
|
||||
instruction sequences after LPM.
|
||||
|
||||
FLASHEND is defined in the ioXXXX.h file.
|
||||
USHRT_MAX is defined in <limits.h>. */
|
||||
|
||||
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
|
||||
|| defined(__AVR_ATmega323__)
|
||||
|
||||
/* Alternate: ATmega161/163/323 and 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_alternate(address)
|
||||
#define boot_page_write(address) __boot_page_write_alternate(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_alternate()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
|
||||
|
||||
#elif (FLASHEND > USHRT_MAX)
|
||||
|
||||
/* Extended: >16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_extended_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_extended_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#else
|
||||
|
||||
/* Normal: 16 bit address */
|
||||
#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
|
||||
#define boot_page_erase(address) __boot_page_erase_short(address)
|
||||
#define boot_page_write(address) __boot_page_write_short(address)
|
||||
#define boot_rww_enable() __boot_rww_enable_short()
|
||||
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||
|
||||
#endif
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_fill() except it waits for eeprom and spm operations to
|
||||
complete before filling the page. */
|
||||
|
||||
#define boot_page_fill_safe(address, data) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_fill(address, data); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_erase() except it waits for eeprom and spm operations to
|
||||
complete before erasing the page. */
|
||||
|
||||
#define boot_page_erase_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_erase (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_page_write() except it waits for eeprom and spm operations to
|
||||
complete before writing the page. */
|
||||
|
||||
#define boot_page_write_safe(address) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_page_write (address); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_rww_enable() except waits for eeprom and spm operations to
|
||||
complete before enabling the RWW mameory. */
|
||||
|
||||
#define boot_rww_enable_safe() \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_rww_enable(); \
|
||||
} while (0)
|
||||
|
||||
/** \ingroup avr_boot
|
||||
|
||||
Same as boot_lock_bits_set() except waits for eeprom and spm operations to
|
||||
complete before setting the lock bits. */
|
||||
|
||||
#define boot_lock_bits_set_safe(lock_bits) \
|
||||
do { \
|
||||
boot_spm_busy_wait(); \
|
||||
eeprom_busy_wait(); \
|
||||
boot_lock_bits_set (lock_bits); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _AVR_BOOT_H_ */
|
||||
Reference in New Issue
Block a user