Hi,
I want to ask that Atmega32 is Big Endian or Little Endian?
How we came to know that by using code?
Thanks.
Hi,
I want to ask that Atmega32 is Big Endian or Little Endian?
How we came to know that by using code?
Thanks.
It is little endian. One way to find out is:
uint16_t n = 0x1234; uint8_t * p = (uint8_t *)&n; int main(void) { PORTB = p[0]; PORTB = p[1]; }
Run that and you will see 0x34 written first and then 0x12 afterwards. If it had been big endian it would be 0x12 then 0x34.
Of course this is just avr-gcc and it chooses to store uint16_t in low byte, high byte order. I guess another C compiler for AVR might choose to use big endian (except that none do).
EDIT: Forgot to say that I suppose the true test is to compile an opcode like:
rjmp here here:
The opcode for that is 0xC000. If you look at that stored in code flash it will be 0x00 and the 0xC0, not the other way around.
Hi,
I am not getting that last statements about opcode.
The AVR is a microcontroller. At the end of the day it just executes opcodes that your program into it. Atmel tell you there are about 130+ powerful instructions but in reality a lot are duplicates so there's about 75 distinct opcodes. They are all documented (including the duplicates) in this manual:
http://www.atmel.com/Images/Atme...
If you look through the alphabetic list there you will come across (for example) RJMP = Relative Jump:
As you can see from the description of the opcode there it will be 0xC??? where ??? represents some relative offset to jump. As I say, if you used:
rjmp here here:
then the offset part is 000 so the complete opcode is 0xC000. It is stored into the flash of the AVR. The CPU sequentially fetches such 16 bit words and executes them. But if you read the flash byte by byte you will find that the order of the bytes in this case is 0x00 then 0xC0 (that is low byte then high byte) rather then 0xC0 then 0x00 (high byte then low byte) so this make it "little endian".
I seem to remember (though I'd have to run some code to verify) but the ONE place the AVR does not operate in a little endian way is when it pushes a function return address onto the stack. It's true that the PUSHs themselves are low byte then high byte but the way a stack works "backwards" means that if you examine the two (or three) return address bytes in RAM you will find high to low. So if the opcode:
rcall foo here:
where used, where "here" is location 0x1234. Then the CPU would PUSH 0x34 then 0x12 so in memory you would find 0x12 then 0x34 in big endian order. But this is simply because of the backward nature of stacks.
Little Endian means the higher order bytes of multibyte values are stored in the higher addresses. You can see in various aspects of the design that AVR is little endian. The opcodes were already mentioned, but also:
Instructions that use register pairs use little endian convention, for example the result of MUL goes to r0 (low byte) and r1 (high byte).
Peripheral registers that are 16 bit also have addresses according to the little endian convention (high byte is in the high address).
The stack pointer is also organized this way.
But there is one exception: return addresses of subroutines are pushed in the stack in such way that they end up in big endian format.
How I am going to see output means result of program on Atmel studio 7 for endianness.We can see result in C on output screen,so how it can be seen on Atmel Studio?
Run the simulator.
I got the concept of little endian and big endian.Only stuck in program .and output.
As I am new on Atmel Studio I dont know how to see output like in C.
#include <avr/io.h>
uint16_t n = 0x3;
uint8_t * p = (uint8_t *)&n;
int main(void)
{
PORTB = p[0];
PORTB = p[1];
}
How I am going to check result for this code?? for endianness
Just tell me how to check output??
As I am new on Atmel Studio I dont know how to see output like in C.
$ cat test10.c #include <stdio.h> int main(void) { int i; for (i = 0; i < 10; i++) { printf("i = %d\n", i); } return 0; } $ gcc test10.c -o test10 $ ./test10 i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 $
then as you can see here, it's best done on a PC - you get to see an instant result.
To achieve the same on a micro like an AVR you first have to think of some kind of output device you want to connect. Popular choices are things like an LCD display or a UART link to a PC (usually over USB). In the latter case you then do something like:
$ cat avr.c #include <stdio.h> #include <avr/io.h> void uart_init(void) { UBRRL = 51; // 9600 baud on 8MHz UCSRB = (1 << TXEN) | (1 << RXEN); // UART on } int uart_putchar(char c, FILE *stream) { // wait until clear to send while (!(UCSRA & (1 << UDRE))); UDR = c; return 0; } int uart_getchar(FILE *stream) { // wait for character to arrive while (!(UCSRA & (1 << RXC))); return UDR; } FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); int main(void) { int i; uart_init(); stdout = stdin = &uart_str; for (i = 0; i < 10; i++) { printf("i = %d\n", i); } return 0; }
I haven't tested that (or even tried to compile it) but that is about the minimum of what you need in a micro to make the UART work. As I wrote it, it relies on the micro running at 8MHz. If it isn't it won't work. I also have issues about how to get the TXD/RXD signals to the PC and display them there.
When I wrote the above:
uint16_t n = 0x1234; uint8_t * p = (uint8_t *)&n; int main(void) { PORTB = p[0]; PORTB = p[1]; }
I rather assumed one would build that, program it in to an AVR, connect to the AVR with an ICE debugger and then single-step the code to see what actually goes to "PORTB" for the two writes.
If you don't have an ICE (or a micro that can use one) then I guess the alternative is to head off down the UART or LCD route.
But why, we've told you it is little endian - don't you believe us? ;-)
Clawson said: "But why, we've told you it is little endian - don't you believe us? ;-)" I would add, why does it matter?
I rather imagine the course tutor has posed the question "is AVR little/big endian and how do you prove it?" ;-)
I still think this proves it:
$ cat endian.S rjmp here here: $ avr-gcc -mmcu=avr1 -nostartfiles endian.S -o endian.elf $ avr-objcopy -O binary endian.elf endian.bin $ hexdump -C endian.bin 00000000 00 c0 |..| 00000002
Just create an assembly project in Atmel Studio, then paste this code:
call far_label .org 0x1234 far_label: ret
Then build it an run the debugger. See how the address 0x1234 is represented in the program flash memory as part of the call instruction encoding.
Now, be honest with us: you're the "flash 3 LEDs" guy, right?
#Clawson Your explanation is inef for understanding.Thanks.
Flash 3 Leds? I am asking about endianess concept.
Thanks Clawson.
Yes Ofcourse .only I just want to check my logic regarding endianess.Btw Thanks for explaning.
#include <avr/io.h> uint16_t n = 0x3; uint8_t * p = (uint8_t *)&n; int main(void) { PORTB = p[0]; PORTB = p[1]; }
This one is easy. Step through it with the simulator. First, it will set PORTB to either 3, or 0. If it's 3, then AVR is little endian. If it's 0, then AVR is big endian.
Why does it matter? It matters in communication with some outside system. If you're outputting a binary representation of 5280, and your AVR sends A0, 14 as a little endian machine, but the outside system is big endian and expects 14, A0; your probe will crash into Neptune instead of...
Thanks