Flashing a sketch from SD card using 2boot bootloader

osbock sent me a compiled hex for arduino ethernet (CS is digital 4) but it didn't work for me, here is the HEX so you give it a try as well.

http://dl.dropbox.com/u/18771283/ArduinoEthernetSD.hex

Don't forget that the sketch to be uploaded has to be in .BIN not .HEX and that this is a 4K bootloader so you need to change fuses accordingly.

Here are the avrdude commands that worked for me. Unfortunately I don't have an arduino ethernet to test:

avrdude -c usbtiny -p m328p -e -u -U lock:w:0x3f:m -U efuse:w:0x05:m -U hfuse:w:0xD8:m -U lfuse:w:0xFF:m
avrdude -c usbtiny -p m328p -U flash:w:ArduinoEthernetSD.hex -U lock:w:0x0f:m

of course change the -c option if you have a different programmer (and add baud and other things if you need em.)

eudaldcp:
I really dont know wich value I have to put in the BOOT_ADR field. Im using an Atmega328p

I use

MCU_TARGET  = atmega328p    	# Target device to be used (32K or lager)
BOOT_ADR    = 0x3800	# Boot loader start address [byte]
F_CPU       = 16000000	# CPU clock frequency [Hz]

but still doesn't work. I guess the arduino ethernet is more picky..

It still not working...

Let me sumarize the steps I did:
1st: change asmfunc.S so I have:

#define DDR_CS _SFR_IO_ADDR(DDRD), 4 // MMC CS pin (DDR, PORT)
#define PORT_CS _SFR_IO_ADDR(PORTD), 4

#define DDR_CK _SFR_IO_ADDR(DDRB), 5 // MMC SCLK pin (DDR, PORT)
#define PORT_CK _SFR_IO_ADDR(PORTB), 5

#define DDR_DI _SFR_IO_ADDR(DDRB), 3 // MMC DI pin (DDR, PORT)
#define PORT_DI _SFR_IO_ADDR(PORTB), 3

#define PIN_DO _SFR_IO_ADDR(PINB), 4 // MMC DO pin (PIN, PORT)
#define PORT_DO _SFR_IO_ADDR(PORTB), 4

2nd: change the makefile to:

MCU_TARGET = atmega328p # Target device to be used (32K or lager)
BOOT_ADR = 0x7000 # Boot loader start address [byte]
F_CPU = 16000000 # CPU clock frequency [Hz]

3th: compile and burn the hex file with:

avrdude -c avrisp -p m328p -P /dev/tty.usbmodem12341 -b 19200 -e -u -U lock:w:0x3f:m -U efuse:w:0x05:m -U hfuse:w:0xD8:m -U lfuse:w:0xFF:m
avrdude -c avrisp -p m328p -P /dev/tty.usbmodem12341 -b 19200 -U flash:w:avr_boot.hex -U lock:w:0x0f:m

4th: compile some app (the blink one) and take the .elf file and do:

avr-objcopy -I elf32-avr -O binary Blink.cpp.elf app.bin

5th and final:
burn that bin file to my 2GB FAT32 uSD and try it, but is not working, the led is not blinking :frowning:
*I also tried with FAT16

Am I missing something?????

ok, I think that I found what is wrong, but I dont know how to fix it...

As you can see on: http://arduino.cc/en/Main/ArduinoEthernetShield

"Note that because the W5100 and SD card share the SPI bus, only one can be active at a time. If you are using both peripherals in your program, this should be taken care of by the corresponding libraries. If you're not using one of the peripherals in your program, however, you'll need to explicitly deselect it. To do this with the SD card, set pin 4 as an output and write a high to it. For the W5100, set digital pin 10 as a high output. "

So, I should set PORTB 2 as high output In that assembler asmfunc.S.... But I dont know how! Does anybody knows how?

Thanks!!

UPDATE: I finally did it! for the people who have arduino ethernet, change the mmc.c file by: ( I just added a few lines before the call of init_spi() and the defines and includes). If anybody can do the same in the assembler file, it would be better.

/-----------------------------------------------------------------------/
/ PFF - Generic low level disk control module (C)ChaN, 2010
/------------------------------------------------------------------------/
/
/ Copyright (C) 2010, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/------------------------------------------------------------------------/
/
Dec 6, 2010 First release
*/

#include "pff.h"
#include "diskio.h"
#include <avr/io.h>

void init_spi (void); /* Initialize SPI port (asmfunc.S) /
void deselect (void); /
Select MMC (asmfunc.S) /
void select (void); /
Deselect MMC (asmfunc.S) /
void xmit_spi (BYTE d); /
Send a byte to the MMC (asmfunc.S) /
BYTE rcv_spi (void); /
Send a 0xFF to the MMC and get the received byte (asmfunc.S) /
void dly_100us (void); /
Delay 100 microseconds (asmfunc.S) */

/*--------------------------------------------------------------------------

Module Private Functions

---------------------------------------------------------------------------*/

#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_SS PB2

/* Definitions for MMC/SDC command /
#define CMD0 (0x40+0) /
GO_IDLE_STATE /
#define CMD1 (0x40+1) /
SEND_OP_COND (MMC) /
#define ACMD41 (0xC0+41) /
SEND_OP_COND (SDC) /
#define CMD8 (0x40+8) /
SEND_IF_COND /
#define CMD16 (0x40+16) /
SET_BLOCKLEN /
#define CMD17 (0x40+17) /
READ_SINGLE_BLOCK /
#define CMD24 (0x40+24) /
WRITE_BLOCK /
#define CMD55 (0x40+55) /
APP_CMD /
#define CMD58 (0x40+58) /
READ_OCR */

/* Card type flags (CardType) /
#define CT_MMC 0x01 /
MMC ver 3 /
#define CT_SD1 0x02 /
SD ver 1 /
#define CT_SD2 0x04 /
SD ver 2 /
#define CT_BLOCK 0x08 /
Block addressing */

static
BYTE CardType;

/-----------------------------------------------------------------------/
/* Send a command packet to MMC /
/
-----------------------------------------------------------------------*/

static
BYTE send_cmd (
BYTE cmd, /* 1st byte (Start + Index) /
DWORD arg /
Argument (32 bits) */
)
{
BYTE n, res;

if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */
cmd &= 0x7F;
res = send_cmd(CMD55, 0);
if (res > 1) return res;
}

/* Select the card */
select();

/* Send a command packet /
xmit_spi(cmd); /
Start + Command index /
xmit_spi((BYTE)(arg >> 24)); /
Argument[31..24] /
xmit_spi((BYTE)(arg >> 16)); /
Argument[23..16] /
xmit_spi((BYTE)(arg >> 8)); /
Argument[15..8] /
xmit_spi((BYTE)arg); /
Argument[7..0] /
n = 0x01; /
Dummy CRC + Stop /
if (cmd == CMD0) n = 0x95; /
Valid CRC for CMD0(0) /
if (cmd == CMD8) n = 0x87; /
Valid CRC for CMD8(0x1AA) */
xmit_spi(n);

/* Receive a command response /
n = 10; /
Wait for a valid response in timeout of 10 attempts */
do {
res = rcv_spi();
} while ((res & 0x80) && --n);

return res; /* Return with the response value */
}

/*--------------------------------------------------------------------------

Public Functions

---------------------------------------------------------------------------*/

/-----------------------------------------------------------------------/
/* Initialize Disk Drive /
/
-----------------------------------------------------------------------*/

DSTATUS disk_initialize (void)
{
BYTE n, cmd, ty, ocr[4];
UINT tmr;

SPI_PORT |= 1<<SPI_SS; //PB2 output: High (deselect other SPI chips)
SPI_DDR |= 1<<SPI_SS; // SPI Data -> Output

init_spi(); /* Initialize ports to control MMC /
for (n = 100; n; n--) dly_100us(); /
10ms delay /
for (n = 10; n; n--) deselect(); /
80 Dummy clocks with CS=H */

ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state /
if (send_cmd(CMD8, 0x1AA) == 1) { /
SDv2 /
for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); /
Get trailing return value of R7 resp /
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /
The card can work at vdd range of 2.7-3.6V /
for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /
Wait for leaving idle state (ACMD41 with HCS bit) /
if (tmr && send_cmd(CMD58, 0) == 0) { /
Check CCS bit in the OCR /
for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /
SDv2 (HC or SC) /
}
}
} else { /
SDv1 or MMCv3 /
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; /
SDv1 /
} else {
ty = CT_MMC; cmd = CMD1; /
MMCv3 /
}
for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /
Wait for leaving idle state /
if (!tmr || send_cmd(CMD16, 512) != 0) /
Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
deselect();

return ty ? 0 : STA_NOINIT;
}

/-----------------------------------------------------------------------/
/* Read partial sector /
/
-----------------------------------------------------------------------*/

DRESULT disk_readp (
BYTE buff, / Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) /
DWORD lba, /
Sector number (LBA) /
WORD ofs, /
Byte offset to read from (0..511) /
WORD cnt /
Number of bytes to read (ofs + cnt mus be <= 512) */
)
{
DRESULT res;
BYTE rc;
WORD bc;

if (!(CardType & CT_BLOCK)) lba = 512; / Convert to byte address if needed */

res = RES_ERROR;
if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */

bc = 40000;
do { /* Wait for data packet */
rc = rcv_spi();
} while (rc == 0xFF && --bc);

if (rc == 0xFE) { /* A data packet arrived */
bc = 514 - ofs - cnt;

/* Skip leading bytes */
if (ofs) {
do rcv_spi(); while (--ofs);
}

/* Receive a part of the sector */
do {
*buff++ = rcv_spi();
} while (--cnt);

/* Skip trailing bytes and CRC */
do rcv_spi(); while (--bc);

res = RES_OK;
}
}

deselect();

return res;
}

I got it working with the modifications suggested by eudaldcp. Thanks!

I was on a similar track, but I don't have the ethernet, so can't test. I think I know where to change it in asmfunc. I changed it, and if someone could test, I'll put a fork up on github so there'll be an arduino friendly version for folks.

http://baldwisdom.com/data/ArduinoEthernetSDBoot.hex

And the hacked asmfunc.S:
http://baldwisdom.com/data/asmfunc.S

well done osbok! it works with Arduino ethernet
thanks for your contribution!!

I put the code up on github. I need to add more doc, improve the makefile, etc but it's there for use now.

Note: The original author at elm-chan.org published this under a very liberal open source license, so this is legit.
I hope to find his/her actual name so I can at least give credit.

I also forked the code on Github GitHub - mharizanov/avr_boot: Flash Arduino from SD card

My modifications are:

  1. only re-flash if the sketch has changed. the original bootloader flashes everytime, this is not so good.
  2. to achieve the above, I discarded FAT12 compatibility (who uses fat12 anyway)

[edit] for the future I plan that the bootloade reads the firmware name from EEPROM (default will still be "app.bin") so that will allow the applicatiom to re-flash with needed portions by itself.. neat
Also, I will make .HEX compatibility since the .BIN is additional step that isn't really needed

Do you want to work together on this?
I have code for doing the hex file (from my bootdrive project) but I'm wondering if it's worth the space. It's only a small simple command to convert it.

I was going to try to squeeze it down to either:

  1. get it out of the 4k bootloader zone (into at least the 2k zone)
  2. add back serial programming. The Optiboot code is very small and should be easy to integrate (I ported it into my bootdrive code)

Yes, that would be great. I have doubts about the 2K target, I'd rather focus on fixing the 2boots if we go in that direction. I guess it is something really small that is missing to get it working.

My ideal bootloader will have these features, in order of importance:

  • SD card flashing (only if new file is uploaded)
  • EEPROM based firmware file name
  • Serial programming
  • .HEX rather than .BIN
  • 2K

With the EEPROM based firmware file name, the application may switch itself to a TFTP sketch that will run for 20 minutes and revert back to the original application. The TFTP will wait for incomming connection and if found will save the uploaded file to the SD card (new firmare)..

i also have the code for loading from eeprom EDIT: I mean: the code for reading the filename from eeprom

:smiley:

Cool. Can we agree to use one github? We can all be contributors, or we could designate one master and do forks/pulls.

Martin, I like the load only if new, and would incorporate that right away. The LED thing should be under ifdef with some defines to make it board dependent.
I have an idea how to handle this in the makefile (similar to 2boots).

I think it will be best to do it this way. As I am less experienced, I suggest you take the lead.

Hi guys,
I agree to make a colaborative github, also, I would like to give an other chance to the 2boots code. I sent a mail to the main developer of 2boots explaining our problems. I still waiting for an answer...

But 2boots is based in another code => MMC/SD Bootloader füt ATMega16 - Mikrocontroller.net and this one might work for FAT16, if works, we will have 2K extra for including all this stuf!!

This is great.
Martin, I added you as a collaborator to

Eudaldcp, what's your github id?

I spent a lot of time on 2boots, and actually got about 50% done rewriting it using the sdfat library code. It was really hard to debug. I'm hoping that changes when I get the Dragon I ordered (allows breakpoints.)

hold off on putbacks to the repository until I branch (to preserve the current working version.)

Ive just created an account. My ID in github is: eudaldcp :slight_smile:

OK, you are added. WE can probably take this offline to github, unless they are general ideas you feel others would be interested.
I created the v.1 branch which nobody should touch (putback to master)
Later today I'll draft some groundrules. Basically if you are confident with your change, you can put it back directly. If you want a review, it is best to fork the repository, and then do a pull request.

Also, if you have "application specific features" that aren't of general use, you should probably just put those in your own fork. You can have as many as you want.

Hi to everyone, interesting thread.

I've a lot of problems to let it working.
I'm using an arduino ethernet board
4gb Microsd sdhc, partitioned to only 2gb fat16 formatted.

I've dowload the code from here :https://github.com/osbock/avr_boot/downloads

I've compiled and flash fw into my board making only little modifications at the file provided then i've put a app.bin sketch file named in the root of sdcard.
Nothing happen, after reset, app.bin fw not loaded, i can see only the board led (in my board connected to pin9) always on.

Any suggestion?
Thanks in advance.