Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Aug 25, 2007 - 04:37 PM |
|


Joined: Jul 18, 2005
Posts: 50115
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Lee,
Nope "return;" doesn't generate anything in a "naked" function. However, when I returned them to "normal" functions there were no PUSH/POPs generated anyway as the only register being used (so far) was R24 which is a "clobbered" register anyway. So I can drop that use of asm().
I also found I could generate exactly the same preamble as normal with the C code:
Code:
#define SPH _SFR_IO8(0x3E)
#define SPL _SFR_IO8(0x3D)
register uint8_t myR1 asm("r1");
myR1 = 0; //C uses R1 as __zero_reg
SREG = myR1;
SPH = 0x4;
SPL = 0x5F;
So I can stick with -nostdlib and don't need to use asm() here either - well apart from the register binding - but that's just GCC's syntax to bind a var to a register. Next I need to code the equivalent of the __do_copy_data loop.
What I'm going to do is target the mega16 initially just to get a core working on an AVR I happen to have in the bit box then later flesh it out with #ifdef'd stuff to be more generic. That's why I don't mind hard coding the 0x45F above for the time being and can later just strip this from the part specific .h file.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Aug 25, 2007 - 05:34 PM |
|


Joined: Jul 18, 2005
Posts: 50115
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I've now got this that handles the whole of the usual C pre-amble stuff (that I need) without any baggage (that I don't want):
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>
#define SPH _SFR_IO8(0x3E)
#define SPL _SFR_IO8(0x3D)
typedef void (*p_fn_t)(void);
uint8_t commands[] = { 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D',
'e', 'E', 'F', 'g', 'l', 'L', 'm', 'N',
'p', 'P', 'Q', 'r', 'R', 's', 'S', 't',
'T', 'V', 'x', 'y' };
register uint8_t myR1 asm("r1");
register uint8_t ch asm("r5");
extern unsigned char * _etext;
void uartGet(void) __attribute__ ((noinline));
void uartGet(void){
ch = UDR;
}
void cmd_a(void){
UDR = 'a';
return;
}
void cmd_A(void){
UDR = 'A';
}
p_fn_t funcs[] = { cmd_a, cmd_A };
int main(void) __attribute__ ((section(".init3"))) __attribute__ ((naked));
int main(void)
{
register uint8_t i;
register uint8_t *src_ptr = (uint8_t *) &_etext;
register uint8_t *dst_ptr = (uint8_t *) 0x60;
myR1 = 0;
SREG = myR1;
SPH = 0x4;
SPL = 0x5F;
for (i=0; i<(sizeof(commands)+sizeof(funcs)); i++) {
*dst_ptr++ = pgm_read_byte(src_ptr++);
}
while (1) {
uartGet();
for (i=0; i<sizeof(commands); i++) {
if (ch == commands[i]) {
funcs[i]();
}
}
}
}
|
_________________
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 01:21 AM |
|


Joined: Sep 04, 2002
Posts: 17683
Location: Orlando Florida
|
|
| How come uartget doesnt check the rx ready bit? |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 02:12 AM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
Anyone want to test my 4AvrAscii 256 BabyBootloader? 508 bytes with WinAVR20060421. I've been trying to 'break' it on my mega88 (on an stk500). I generated an intel hex file that uses the complete program memory, and it keeps working (uploading without error, that is). I also throw big files of any type at it, and it keeps working (errors of course, though). It compiles to the same size on mega88/168/16 (only tested on a mega88 though).
I tried to use WinAVR20070525, but it produces 60 more bytes. It seems to want to inline my sendchar function every time its used. I set the function to 'noinline', which fixes that, but still have some extra bytes (still over 512). Same settings, same makefile, same avr studio (latest available). I'll just stick with the older version, I guess, or learn to 'beat' the new version into submission, and get it to do want I want.
Can I ask a basic Avr101 question or two? Thanks. r0-r31, where can I find in the datasheets what the initial state of those registers are? Obviously not 0, otherwise there would be no need to clear r1 for the compiler. I assume that only registers in I/O space are 'initialized'. I guess I just want to see somewhere where it says- 'registers r0-r31 are are in an unknown state on powerup' (what about non-powerup resets?). I'm probably looking right at in the datasheet, but don't see it. |
|
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 03:30 AM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
I have been driving myself crazy. Trying to compile/simulate for mega88/168/16. Forgetting to switch the simulator to the correct avr, forgetting to add -mshort-calls, etc. I have been using WinMerge to compare lss listings, to see what's going on. The weird thing is that without -mshort-calls, the mega88 and the mega16 compiled to the exact same size (so I didn't realize I forgot the -mshort-calls). The mega16 has i/o registers that use in/out compared to the same registers in the mega88 that need lds instead. But the mega16 was using call (2 words) instead of rcall(1 word). It all cancelled out, leaving the same size, and getting me confused. Until I compiled for the mega168. Then the light bulb turned on.
So, the mega16 compiles to 474bytes. But I'm assuming the worst case and am not going to put that to use. (worst case = mega88/168 that uses lds, setting SP even if not needed).
Is there a (simple) way to determine which avr's have SP already set? (like if all avr's with a certain register name have the sp setup already). |
|
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 01:09 PM |
|


Joined: Jul 18, 2005
Posts: 50115
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
bobgardner wrote:
How come uartget doesnt check the rx ready bit?
Bob,
Oh this is just a prtotype to test the ICALL concept. It's not working code. The RXC checking in uartGet comes later as do the 30 odd cmd_<letter> functions that actually do all the various functions. I also need the stuff to enter the app if the bootloader is not invoked.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 01:12 PM |
|


Joined: Jul 18, 2005
Posts: 50115
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
curtvm wrote:
Can I ask a basic Avr101 question or two? Thanks. r0-r31, where can I find in the datasheets what the initial state of those registers are? Obviously not 0, otherwise there would be no need to clear r1 for the compiler.
Oh no I think that at power on r0-r31 will contain 0 (though I can't say I've ever seen this written down anywhere) but the reason the C preamble does the "eor r1,r1" to put 0 into _zero_reg is simply because the start at 0x0000 may NOT have been a power on reset but a jump there for some other reason after the AVR's alredy been running and the registers might have been set to anything.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 02:12 PM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
Thanks. The avr studio simulator certainly thinks they will be 0 after a reset, so I guess that's our documentation (I tried to figure out how the simulator knew that those registers were to be cleared on reset, but could not find any reference to R0-R31 in the xml files, so it must be hard coded in the simulator and all avr's must clear them on reset). You would think some datasheet or appnote would tell us. Or maybe its just common knowledge, or so obvious.
I'm only running the bootloader on resets, so I think I'll eliminate clearing r1. (2 more bytes available).
I keep finding ways to get a few extra bytes, then keep finding ways to use them up again. |
|
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 02:42 PM |
|


Joined: Feb 19, 2001
Posts: 22734
Location: Wisconsin USA
|
|
|
Quote:
(though I can't say I've ever seen this written down anywhere)
IIRC that was one of my first posts, asking this question. I'm almost sure that it is explicitly stated. I'll have to do some serious Search-ing.
Lee |
|
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 10:48 PM |
|

Joined: Nov 09, 2005
Posts: 34
|
|
|
bobgardner wrote:
The 'field upgradeable by the customer' feature of a product is viewed as a plus ..
If the power goes out right in the middle of the process, I'd suggest that something is out to get him and better not go outside for a few days.
http://www.etc.ugal.ro/cchiculita/software/picbootloader.htm
Tiny PIC Bootloader. Not AVR, but may give some ideas on programming.. Maybe mentioned already, I haven't gone through and read the entire thread yet..
And hear hear for field programmable. You might even consider an IR module, easy thing to tack on every design at $.25 or so. Shared on a pin that won't matter if there's interference on the odd occasion and it doesn't even take a pin. Just look for a preamble for a second on boot, then wait for update if you see it.. While there are IRDA etc for really high speed, there are some high data rate normal modules that are still cheap with 4x the data speed.
And flash should almost never ever have a problem updating, if it does you just got caught with your pants down. Set reset vector to your bootloader routine, to start bootloading. Read in a secondary bootloader in a different area, checksum, then set vector and go to it. Read in your new permanent bootloader and put it in it's place, checksum, vector to it. Now do the rest of the bootload and checksum it, leaving your reset vector set to the new bootloader until you've checksummed the new code. Where you go on reset should always be aimed at previously checksummed code, do this correctly and double blind your reset vector changes and even a 'bad' flash will just end up sitting there waiting to finish the bootload. Short of a hardware failure there should never be a 'bad flashing', there's just a lot of slack programming out there and people have gotten used to the 'bad flash' idea. I believe in quick and dirty, but for this it's easy to make two copies of 'quick and dirty' and change the vector and do a checksum and make it nearly bullet proof, it's not much work to do..
Alan
[/u] |
|
|
| |
|
|
|
|
|
Posted: Aug 26, 2007 - 11:22 PM |
|

Joined: Dec 18, 2001
Posts: 3843
|
|
|
bobgardner wrote:
I have 128 words free in my mega16 (256 bytes). Is there a bootloader that will fit? I know BLIPS and Megaload will fit in 256 words... Not matter what I try, I can't squeeze it down enough to have 256 words free....
The mega8 allows for a 128 word boot memory size.
One could easily code, in assembly, a bootloader that is no-frills and fits in that space. Don't know what the smaller chips have for min size of boot area. |
|
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 12:45 AM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
|
stevech wrote:
The mega8 allows for a 128 word boot memory size.
One could easily code, in assembly, a bootloader that is no-frills and fits in that space. Don't know what the smaller chips have for min size of boot area.
He's got 256 words free now. He also does not want to use the boot reset fuse, so it doesn't matter what size the bootloader section is set to (as long as the spm instruction is in the bootloader section). He is using a mega16 which does 128/256/512/1024word sizes for bootloader.
There is never enough bootloaders in the world. So we are on a quest to increase their numbers.
To save the planet. |
|
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 02:02 AM |
|


Joined: Sep 04, 2002
Posts: 17683
Location: Orlando Florida
|
|
| I cant wait to have an avr on a net somewhere so I can use Steve Childress BLIPs UDP bootload feature. |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 04:32 AM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
Anybody know about encryption (or obfuscation)? I am going to try some (easy) form of 'encryption', but maybe I'm not thinking this through right.
I've got 256words (bootloader code), 4096bits, as my 'key'.
Hypothetical scenario-
My long-named bootloader is in a super-duper device (if any mega88 device can qualify as super-duper). I need to have a 'client' update the firmware, but don't want to 'give' my code away (also assuming I fused the lock bits correctly).
My bootloader has no read command, only erase w/verify, write w/verify. I 'encrypt' the intel hex file data bytes (DD fields) with my bootloader code (just xor). The 'client' will get an intel hex file from me, which is still ascii, looks normal, but the data fields are xor'd with my bootloader code, which the 'client' does not know, or can know. The data bytes in the intel hex record will not make any sense unless you have my 'key' (bootloader code). LL, AAAA, TT, and CC will stay unencrypted.
BLB1 Mode 3 will protect the bootloader, and prevent an application from reading the bootloader (my key, and method). So if they wanted to get clever, and put in their own application (unencrypted mode), it will not be able to read my bootloader.
Will work? Maybe work? Who cares? Seriously Flawed? None of the above?
(I need to free up a few more bytes, though). |
|
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 05:45 AM |
|

Joined: Dec 18, 2001
Posts: 3843
|
|
|
Quote:
He's got 256 words free now. He also does not want to use the boot reset fuse, so it doesn't matter what size the bootloader section is set to (as long as the spm instruction is in the bootloader section)
Hmmm, if you don't set the boot reset fuse, then how can you get to the bootloader if the application is hosed up?
Unrelated but interesting: Working with the ARM7 chips from NXP/Philips. They seem to have a serial port bootloader programmed in at time of manufacture, and the code/protocol is apparently hard to know/proprietary. |
|
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 06:14 AM |
|

Joined: Sep 21, 2005
Posts: 2224
|
|
|
stevech wrote:
Hmmm, if you don't set the boot reset fuse, then how can you get to the bootloader if the application is hosed up?
I'm a member of the choir, but Bob isn't. He's planning on just looking for the esc-esc in his app, then jump to the bootloader. I'm not doing a good job of converting the 'lost', but maybe they will listen to you. (I haven't tried the fire and brimstone method yet).
(the Boot Reset Fuse people are called the 'BRusers', the others are called 'Zeros' )
stevech wrote:
Unrelated but interesting: Working with the ARM7 chips from NXP/Philips. They seem to have a serial port bootloader programmed in at time of manufacture, and the code/protocol is apparently hard to know/proprietary.
I was just thinking that eventually atmel will put their own bootloader in these things (like ti msp430?). |
|
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 01:23 PM |
|


Joined: Sep 04, 2002
Posts: 17683
Location: Orlando Florida
|
|
| Curt... you must have a much higher opinion of the typical consumer than I do... You sell them a gizmo with an avr in it, and they use it, and you come out with an upgrade, and they dl the hex file and upgrade in the field. Its a win for both of you. Dont have to send the thing across the country to plug in the JTAG. So what if they disassemble the hex file? If they try to put some 'feature' in the program that you didnt design, it will probably fail miserably. My experience is it takes me at least 3 edits to put any trivial feature in my own program. Most consumers will be lucky to be able to master connecting the laptop db9 to run the bootloader. |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 06:45 PM |
|

Joined: Jul 22, 2005
Posts: 288
Location: Lenexa, KS
|
|
|
Quote:
Unrelated but interesting: Working with the ARM7 chips from NXP/Philips. They seem to have a serial port bootloader programmed in at time of manufacture, and the code/protocol is apparently hard to know/proprietary.
We have a iMXL (Dragonball) that has something similar. You strap a pin and the boot loader springs to life. It's well documented on that. We used it a bunch during early development. It's probably an ARM thing more than Freescale or NXP.
This is the reason I prefer using the BOOTRST fuse and protect the loader. The application is not loader aware. If the right condition exists on reset, the loader runs, otherwise, the application runs. Almost a hardware thing like on the ARM processor. I think this is the back door the kid used to hack the iPhone. |
_________________ official AVR Consultant
www.veruslogic.com
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 07:08 PM |
|


Joined: Sep 04, 2002
Posts: 17683
Location: Orlando Florida
|
|
| So there are 2 types of products... those that 'have no user servicable parts inside', and those that the user gets to reflash when there is a firmware update on the company website. Its not like you were posting the c source. What can they do with a hex file? |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Aug 27, 2007 - 07:11 PM |
|


Joined: Jul 18, 2005
Posts: 50115
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
I have a strong feeling this is NOT the way to go about doing this in 512 bytes. Already this is 334 bytes and I haven't filled in any of the "complex" functions:
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "defines.h"
#define SPH _SFR_IO8(0x3E)
#define SPL _SFR_IO8(0x3D)
typedef void (*p_fn_t)(void);
typedef union {
uint8_t bytes[2];
uint16_t word;
} split_t;
uint8_t commands[] = { 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D',
'e', 'E', 'F', 'g', 'l', 'L', 'm', 'N',
'p', 'P', 'Q', 'r', 'R', 's', 'S', 't',
'T', 'V', 'x', 'y' };
register uint8_t myR1 asm("r1");
register uint8_t ch asm("r24");
register split_t address asm("r18");
extern unsigned char * _etext;
void uartSend(void) __attribute__ ((noinline));
void uartSend(void)
{
UART_DATA_REG = ch; // prepare transmission
while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)));// wait until byte sendt
UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT); // delete TXCflag
}
void uartGet(void) __attribute__ ((noinline));
void uartGet(void){
while(!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT))); // wait for data
ch = UART_DATA_REG;
}
void uartSendY(void) __attribute__ ((noinline));
void uartSendY(void){
ch = 'Y';
uartSend();
}
void uartSendCR(void) __attribute__ ((noinline));
void uartSendCR(void){
ch = '\r';
uartSend();
}
// auto-increment supported?
void cmd_a(void){
uartSendY(); // Yes we support auto-increment
}
// set 'address'
void cmd_A(void){
uartGet(); // Set 'address'
address.bytes[1] = ch;
uartGet();
address.bytes[0] = ch;
uartSendCR();
}
// check for block mode support
void cmd_b(void) {
uartSendY(); // Yes we suppport block mode
ch = ((PAGESIZE>>8) & 0xFF); // MSB first.
uartSend();
ch = (PAGESIZE&0xFF); // Report BLOCKSIZE (bytes).
uartSend();
}
// Block mode programming
void cmd_B(void) {
}
// write program memory low byte
void cmd_c(void) {
}
// write program memory high byte
void cmd_C(void) {
}
// read EEPROM byte
void cmd_d(void) {
}
// write EEPROM byte
void cmd_D(void) {
}
// chip erase
void cmd_e(void) {
}
// exit bootloader
void cmd_E(void) {
}
// read low fuse bits
void cmd_F(void) {
}
// block read
void cmd_g(void) {
}
// write lock bits
void cmd_l(void) {
}
// enter/leave programming mode (just answer \r)
void cmd_LP(void) {
uartSendCR();
}
// write page
void cmd_m(void) {
}
// read high fuse bits
void cmd_N(void) {
}
// get programmer type (S=serial)
void cmd_p(void) {
ch = 'S';
uartSend();
}
// read extended fuse bits
void cmd_Q(void) {
}
// read lock bits
void cmd_r(void) {
}
// read program memory
void cmd_R(void) {
}
// send signature bytes
void cmd_s(void) {
ch = SIGNATURE_BYTE_3;
uartSend();
ch = SIGNATURE_BYTE_2;
uartSend();
ch = SIGNATURE_BYTE_1;
uartSend();
}
// return programmer identifier "AVRBOOT"
void cmd_S(void) {
ch = 'A';
uartSend();
ch = 'V';
uartSend();
ch = 'R';
uartSend();
ch = 'B';
uartSend();
ch = 'O';
uartSend();
ch = 'O';
uartSend();
ch = 'T';
uartSend();
}
// return supported PARTCODE
void cmd_t(void) {
#if PARTCODE+0 > 0
ch = PARTCODE; // Supports only this device, of course.
uartSend();
#endif /* PARTCODE */
ch = 0; // Send list terminator.
uartSend();
}
void cmd_Txy(void) {
uartGet(); // absorb ignored character
uartSendCR();
}
// send software version "15"
void cmd_V(void) {
ch = '1';
uartSend();
ch = '5';
uartSend();
}
p_fn_t funcs[] = { cmd_a, // auto-increment supported?
cmd_A, // set 'address'
cmd_b, // check for block mode support
cmd_B, // Block mode programming
cmd_c, // write program memory low byte
cmd_C, // write program memory high byte
cmd_d, // read EEPROM byte
cmd_D, // write EEPROM byte
cmd_e, // chip erase
cmd_E, // exit bootloader
cmd_F, // read low fuse bits
cmd_g, // block read
cmd_l, // write lock bits
cmd_LP, // enter/leave programming mode (just answer \r)
cmd_m, // write page
cmd_N, // read high fuse bits
cmd_p, // get programmer type (S=serial)
cmd_LP, // enter/leave programming mode (just answer \r)
cmd_Q, // read extended fuse bits
cmd_r, // read lock bits
cmd_R, // read program memory
cmd_s, // send signature bytes
cmd_S, // return programmer identifier "AVRBOOT"
cmd_t, // return supported PARTCODE
cmd_Txy, // ignored LED function
cmd_V, // send software version "15"
cmd_Txy, // ignored LED function
cmd_Txy // ignored LED function
};
int main(void) __attribute__ ((section(".init3"))) __attribute__ ((naked));
int main(void)
{
register uint8_t i;
register uint8_t *src_ptr = (uint8_t *) &_etext;
register uint8_t *dst_ptr = (uint8_t *) 0x60;
myR1 = 0;
SREG = myR1;
SPH = 0x4;
SPL = 0x5F;
for (i=0; i<(sizeof(commands)+sizeof(funcs)); i++) {
*dst_ptr++ = pgm_read_byte(src_ptr++);
}
BAUD_RATE_LOW_REG = BRREG_VALUE;
UART_CONTROL_REG = (1<<ENABLE_TRANSMITTER_BIT) | (1<<ENABLE_RECEIVER_BIT);
// loop here waiting for a character that is not ESC for a while
// enter while() with 'ch' already holding a command code
while (1) {
for (i=0; i<sizeof(commands); i++) {
if (ch == commands[i]) {
funcs[i]();
}
}
uartGet();
}
}
|
_________________
|
| |
|
|
|
|
|
|
|
|