Skip to content

Commit d88a55c

Browse files
committed
ATmega support
1 parent 3a9613c commit d88a55c

File tree

11 files changed

+474
-14
lines changed

11 files changed

+474
-14
lines changed

README.md

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11

2-
# Arduino library to upload sketch over network to Arduino board (SAMD, nRF5)
2+
# Arduino library to upload sketch over network to supported Arduino board
33

44
This library allows you to update sketches on your board over WiFi or Ethernet.
5-
It requires an Arduino SAMD board like Zero, M0 or MKR or a nRF5 board supported by nRF5 core.
65

76
The library is a modification of the Arduino WiFi101OTA library. For more information about how to use this library please visit
87
https://www.arduino.cc/en/Reference/WiFi101OTA
98

9+
## Supported microcontrollers
10+
11+
* ATmega AVR with at least 64 kB of flash (Arduino Mega, [MegaCore](https://github.com/MCUdude/MegaCore) MCUs, MightyCore 1284p and 644)
12+
* Arduino SAMD boards like Zero, M0 or MKR
13+
* nRF5 board supported by [nRF5 core](https://github.com/sandeepmistry/arduino-nRF5).
14+
1015
## Supported libraries
1116

1217
* Ethernet library - shields and modules with Wiznet 5100, 5200 and 5500 chips
@@ -21,6 +26,36 @@ UIPEthernet, WiFiSpi and WiFi library don't support UDP multicast for MDNS, so A
2126

2227
WiFiEsp library for esp8266 with AT firmware failed tests and there is no easy fix.
2328

29+
## ATmega support
30+
31+
The size of networking library and SD library limit the use of ArduinoOTA library to ATmega MCUs with at least 64 kB flash memory. There are other network upload options for here excluded ATmega328p ([Ariadne bootloader](https://github.com/loathingKernel/ariadne-bootloader) for Wiznet chips, [WiFiLink firmware](https://github.com/jandrassy/arduino-firmware-wifilink) for the esp8266).
32+
33+
The ArduinoOTA library ATmega support requires support in bootloader. For the SD storage the MCU must have a 'SD bootloader'. For the InternalStorage the bootloader must be [Optiboot with `copy_flash_pages` function](https://github.com/jandrassy/MegaCore/commit/473c6fcb0a13d2a1d0f5ba578a6ee8933086dc99).
34+
35+
To use remote upload from IDE with SDStorage or InternalStorage, you must [add some lines to platform.txt file](https://github.com/jandrassy/MegaCore/commit/956be74efd5956fde41cae78bac90ff39e536606#diff-3fcd89411a125a3edb58066309f7357c) of your boards package. Packages are located in ~/.arduino15/packages/ on Linux and %userprofile%\AppData\Local\Arduino15\packages\ on Windows (AppData is a hidden folder).
36+
37+
The upload over ArduinoOTA library requires upload of .bin file. To set Arduino IDE to create a .bin file add following lines after existing similar lines:
38+
39+
```
40+
## Create output (bin file)
41+
recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" -O binary {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin"
42+
```
43+
44+
To configure the network upload tool in IDE add following lines to platform.txt file at the end of section "AVR Uploader/Programmers tools".
45+
46+
```
47+
tools.avrdude.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA
48+
tools.avrdude.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b
49+
```
50+
51+
The Arduino AVR core has this lines but the tools.avrdude.upload.network_pattern is different (for Yun). Change it to this version. The upload tool is installed with Arduino AVR core package. At least version 1.2 of the arduinoOTA tool is required.
52+
53+
For SDStorage a 'SD bootloader' is required to load the uploaded file from the SD card. There is no good SD bootloader. 2boots works only with not available old types of SD cards and zevero/avr_boot doesn't yet support USB upload of sketch. The SDStorage was tested with zevero/avr_boot. The ATmega_SD example shows how to use this ArduinoOTA library with SD bootloader.
54+
55+
For upload over InternalStorage Optiboot bootloader with 'copy_flash_pages' function is required. Core packages by MCUdude have Optiboot bootloader for all ATmega boards.
56+
57+
Arduino AVR package doesn't use Optiboot for Arduino Mega. For Arduino Mega install [MegaCore package](https://github.com/MCUdude/MegaCore#boards-manager-installation) and flash the [updated Optiboot bootloader](https://github.com/jandrassy/MegaCore/raw/master/avr/bootloaders/optiboot_flash/atmega2560/optiboot_flash_atmega2560_UART0_115200_16000000L.hex) by replacing the original hex in MegaCore and [using Burn Bootloader in Tools menu in IDE](https://arduino.stackexchange.com/questions/473/how-do-i-burn-the-bootloader). Use MegaCore to upload sketches to Arduino Mega with Optiboot.
58+
2459
## nRF5 support
2560

2661
Note: Only nRF51 was tested for now
@@ -36,7 +71,7 @@ tools.openocd.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA
3671
tools.openocd.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b
3772
```
3873

39-
If you use SoftDevice, stop BLE before applying update. Use `OTEthernet.beforeApply` to register a callbak function. For example in setup `OTEthernet.beforeApply(shutdown);` and add the function to to sketch:
74+
If you use SoftDevice, stop BLE before applying update. Use `OTEthernet.beforeApply` to register a callback function. For example in setup `ArduinoOTA.beforeApply(shutdown);` and add the function to to sketch:
4075

4176
```
4277
void shutdown() {

examples/ATmega_SD/ATmega_SD.ino

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
3+
This example polls for sketch updates over Ethernet, sketches
4+
can be updated by selecting a network port from within
5+
the Arduino IDE: Tools -> Port -> Network Ports ...
6+
7+
Circuit:
8+
* W5100, W5200 or W5500 Ethernet shield with SD card attached
9+
10+
created 13 July 2010
11+
by dlf (Metodo2 srl)
12+
modified 31 May 2012
13+
by Tom Igoe
14+
modified 16 January 2017
15+
by Sandeep Mistry
16+
ArduinoOTA version Dec 2018
17+
by Juraj Andrassy
18+
*/
19+
20+
#include <SPI.h>
21+
#include <SD.h>
22+
#include <Ethernet.h>
23+
#include <ArduinoOTA.h>
24+
25+
// Enter a MAC address for your controller below.
26+
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
27+
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
28+
29+
void setup() {
30+
//Initialize serial:
31+
Serial.begin(9600);
32+
while (!Serial);
33+
34+
// setup SD card
35+
Serial.print("Initializing SD card...");
36+
if (!SD.begin(SDCARD_SS_PIN)) {
37+
Serial.println("initialization failed!");
38+
// don't continue:
39+
while (true);
40+
}
41+
Serial.println("initialization done.");
42+
43+
// start the Ethernet connection:
44+
Serial.println("Initialize Ethernet with DHCP:");
45+
if (Ethernet.begin(mac) == 0) {
46+
Serial.println("Failed to configure Ethernet using DHCP");
47+
} else {
48+
Serial.print(" DHCP assigned IP ");
49+
Serial.println(Ethernet.localIP());
50+
}
51+
52+
// start the OTEthernet library with SD based storage
53+
SDStorage.setUpdateFileName("FIRMWARE.BIN"); // for https://github.com/zevero/avr_boot/
54+
SDStorage.clear(); // AVR SD bootloaders don't delete the update file
55+
ArduinoOTA.begin(Ethernet.localIP(), "Arduino", "password", SDStorage);
56+
57+
}
58+
59+
void loop() {
60+
// check for updates
61+
ArduinoOTA.poll();
62+
63+
// add your normal loop code below ...
64+
}

library.properties

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ name=ArduinoOTA
22
version=1.0.0
33
author=Arduino,Juraj Andrassy
44
maintainer=Juraj Andrassy <[email protected]>
5-
sentence=Update sketches on your SAMD or nRF5 board over WiFi or Ethernet
5+
sentence=Update sketches over WiFi or Ethernet
66
paragraph=Based on WiFi101OTA library. http://www.arduino.cc/en/Reference/WiFi101OTA
77
category=Other
88
url=https://github.com/jandrassy/ArduinoOTA
9-
architectures=samd,nRF5
9+
architectures=*
10+
includes=ArduinoOTA.h

src/ArduinoOTA.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
#define _ARDUINOOTA_H_
2121

2222
#include "WiFiOTA.h"
23+
#ifdef __AVR__
24+
#if FLASHEND >= 0xFFFF
25+
#include "InternalStorageAVR.h"
26+
#endif
27+
#else
2328
#include "InternalStorage.h"
29+
#endif
2430
#ifdef __SD_H__
2531
#include "SDStorage.h"
2632
SDStorageClass SDStorage;
@@ -73,7 +79,7 @@ class ArduinoOTAMdnsClass : public ArduinoOTAClass<NetServer, NetClient> {
7379

7480
};
7581

76-
#if defined(ethernet_h_) // Ethernet library
82+
#if defined(ethernet_h_) || defined(ethernet_h) // Ethernet library
7783
ArduinoOTAMdnsClass <EthernetServer, EthernetClient, EthernetUDP> ArduinoOTA;
7884

7985
#elif defined(WiFiNINA_h) || defined(WIFI_H) // NINA and WiFi101

src/InternalStorage.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
by Juraj Andrassy
2222
*/
2323

24+
#ifndef __AVR__
25+
2426
#include <Arduino.h>
2527

2628
#include "InternalStorage.h"
@@ -153,3 +155,5 @@ long InternalStorageClass::maxSize()
153155
}
154156

155157
InternalStorageClass InternalStorage;
158+
159+
#endif

src/InternalStorageAVR.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright (c) 2018 Juraj Andrassy
3+
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
See the GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#include <Arduino.h>
20+
21+
#if defined(__AVR__) && FLASHEND >= 0xFFFF
22+
23+
#include "InternalStorageAVR.h"
24+
#include "utility/optiboot.h"
25+
26+
InternalStorageAVRClass::InternalStorageAVRClass() {
27+
maxSketchSize = (MAX_FLASH - bootloaderSize) / 2;
28+
maxSketchSize = (maxSketchSize / SPM_PAGESIZE) * SPM_PAGESIZE; // align to page
29+
pageAddress = maxSketchSize;
30+
pageIndex = 0;
31+
}
32+
33+
int InternalStorageAVRClass::open(int length) {
34+
(void)length;
35+
pageAddress = maxSketchSize;
36+
pageIndex = 0;
37+
return 1;
38+
}
39+
40+
size_t InternalStorageAVRClass::write(uint8_t b) {
41+
if (pageIndex == 0) {
42+
optiboot_page_erase(pageAddress);
43+
}
44+
dataWord.u8[pageIndex % 2] = b;
45+
if (pageIndex % 2) {
46+
optiboot_page_fill(pageAddress + pageIndex, dataWord.u16);
47+
}
48+
pageIndex++;
49+
if (pageIndex == SPM_PAGESIZE) {
50+
optiboot_page_write(pageAddress);
51+
pageIndex = 0;
52+
pageAddress += SPM_PAGESIZE;
53+
}
54+
return 1;
55+
}
56+
57+
void InternalStorageAVRClass::close() {
58+
if (pageIndex) {
59+
optiboot_page_write(pageAddress);
60+
}
61+
pageIndex = 0;
62+
}
63+
64+
void InternalStorageAVRClass::clear() {
65+
}
66+
67+
void InternalStorageAVRClass::apply() {
68+
copy_flash_pages_cli(SKETCH_START_ADDRESS, maxSketchSize, (pageAddress - maxSketchSize) / SPM_PAGESIZE + 1, true);
69+
}
70+
71+
long InternalStorageAVRClass::maxSize() {
72+
return maxSketchSize;
73+
}
74+
75+
InternalStorageAVRClass InternalStorage;
76+
77+
#endif

src/InternalStorageAVR.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright (c) 2018 Juraj Andrassy
3+
4+
This library is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 2.1 of the License, or (at your option) any later version.
8+
9+
This library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
See the GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with this library; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
18+
*/
19+
20+
#ifndef _INTERNAL_STORAGE_AVR_H_INCLUDED
21+
#define _INTERNAL_STORAGE_AVR_H_INCLUDED
22+
23+
#include "OTAStorage.h"
24+
25+
class InternalStorageAVRClass : public OTAStorage {
26+
public:
27+
28+
InternalStorageAVRClass();
29+
30+
virtual int open(int length);
31+
virtual size_t write(uint8_t);
32+
virtual void close();
33+
virtual void clear();
34+
virtual void apply();
35+
virtual long maxSize();
36+
37+
private:
38+
uint32_t maxSketchSize;
39+
uint32_t pageAddress;
40+
uint16_t pageIndex;
41+
42+
union {
43+
uint16_t u16;
44+
uint8_t u8[2];
45+
} dataWord;
46+
};
47+
48+
extern InternalStorageAVRClass InternalStorage;
49+
50+
#endif

src/OTAStorage.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,44 @@ static const uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 };
1111
extern "C" {
1212
char * __isr_vector();
1313
}
14+
#elif defined(__AVR__)
15+
#include <avr/wdt.h>
16+
#include <avr/boot.h>
17+
#define MIN_BOOTSZ (4 * SPM_PAGESIZE)
1418
#endif
1519

16-
1720
OTAStorage::OTAStorage() :
1821
#if defined(ARDUINO_ARCH_SAMD)
1922
SKETCH_START_ADDRESS(BOOTLOADER_SIZE),
2023
PAGE_SIZE(pageSizes[NVMCTRL->PARAM.bit.PSZ]),
21-
PAGES(NVMCTRL->PARAM.bit.NVMP),
24+
MAX_FLASH(PAGE_SIZE * NVMCTRL->PARAM.bit.NVMP)
2225
#elif defined(ARDUINO_ARCH_NRF5)
2326
SKETCH_START_ADDRESS((uint32_t) __isr_vector),
2427
PAGE_SIZE((size_t) NRF_FICR->CODEPAGESIZE),
25-
PAGES((uint32_t) NRF_FICR->CODESIZE),
28+
MAX_FLASH(PAGE_SIZE * (uint32_t) NRF_FICR->CODESIZE)
29+
#elif defined(__AVR__)
30+
SKETCH_START_ADDRESS(0),
31+
PAGE_SIZE(SPM_PAGESIZE),
32+
MAX_FLASH((uint32_t) FLASHEND + 1)
2633
#endif
27-
MAX_FLASH(PAGE_SIZE * PAGES)
2834
{
29-
35+
bootloaderSize = 0;
36+
#ifdef __AVR__
37+
cli();
38+
uint8_t highBits = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
39+
sei();
40+
if (!(highBits & bit(FUSE_BOOTRST))) {
41+
byte v = (highBits & ((~FUSE_BOOTSZ1 ) + (~FUSE_BOOTSZ0 )));
42+
bootloaderSize = MIN_BOOTSZ << ((v >> 1) ^ 3);
43+
}
44+
#endif
3045
}
46+
3147
void ExternalOTAStorage::apply() {
48+
#ifdef __AVR__
49+
wdt_enable(WDTO_15MS);
50+
while (true);
51+
#else
3252
NVIC_SystemReset();
53+
#endif
3354
}

src/OTAStorage.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ class OTAStorage {
3838
virtual void apply() = 0;
3939

4040
virtual long maxSize() {
41-
return (MAX_FLASH - SKETCH_START_ADDRESS);
41+
return (MAX_FLASH - SKETCH_START_ADDRESS - bootloaderSize);
4242
}
4343

4444
protected:
4545
const uint32_t SKETCH_START_ADDRESS;
46-
const uint32_t PAGE_SIZE, PAGES, MAX_FLASH;
46+
const uint32_t PAGE_SIZE;
47+
const uint32_t MAX_FLASH;
48+
uint32_t bootloaderSize;
4749

4850
};
4951

src/SDStorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SDStorageClass : public ExternalOTAStorage {
3131
public:
3232

3333
virtual int open(int length) {
34-
_file = SD.open(updateFileName, FILE_WRITE);
34+
_file = SD.open(updateFileName, O_CREAT | O_WRITE);
3535
if (!_file)
3636
return 0;
3737
return 1;

0 commit comments

Comments
 (0)