bianchi77
Advanced Member level 4
- Joined
- Jun 11, 2009
- Messages
- 1,313
- Helped
- 21
- Reputation
- 44
- Reaction score
- 20
- Trophy points
- 1,318
- Location
- California
- Activity points
- 9,442
Friends,
I don't understand on passing parameter on ATMEGA128 and AVR Studio 6,
I tested this function and working find
D0-D4 are appearing
but by the time I put parameter to be passed, it doesn't work
as you can see D0-D4 are missing but rw,rs,and en are working
What do I miss here ? It's very strange for me....
Any experiences , shares or knowledges will be very appreciated,
Thank you
- - - Updated - - -
Is it related with :
How do I pass an IO port as a parameter to a function?
**broken link removed**
I don't understand on passing parameter on ATMEGA128 and AVR Studio 6,
I tested this function and working find
Code:
lcd_cmd()
{
PORTD = 0xFF;
_delay_ms(100);
PORTD = 0x00;
_delay_ms(100);
en=0;
_delay_ms(100);
en=1;
_delay_ms(100);
rs=0;
_delay_ms(100);
rs=1;
_delay_ms(100);
rw=0;
_delay_ms(100);
rw=1;
_delay_ms(100);
}
main()
{
lcd_cmd();
}
but by the time I put parameter to be passed, it doesn't work
Code:
lcd_cmd(unsigned char data_cmd)
{
PORTD = data_cmd;
_delay_ms(100);
PORTD = data_cmd;
_delay_ms(100);
en=0;
_delay_ms(100);
en=1;
_delay_ms(100);
rs=0;
_delay_ms(100);
rs=1;
_delay_ms(100);
rw=0;
_delay_ms(100);
rw=1;
_delay_ms(100);
}
main()
{
while(1)
{
lcd_cmd(0xFF);
_delay_ms(100);
lcd_cmd(0x00);
}
}
as you can see D0-D4 are missing but rw,rs,and en are working
What do I miss here ? It's very strange for me....
Any experiences , shares or knowledges will be very appreciated,
Thank you
- - - Updated - - -
Is it related with :
How do I pass an IO port as a parameter to a function?
**broken link removed**
How do I pass an IO port as a parameter to a function?
Consider this example code:
#include <inttypes.h>
#include <avr/io.h>
void
set_bits_func_wrong (volatile uint8_t port, uint8_t mask)
{
port |= mask;
}
void
set_bits_func_correct (volatile uint8_t *port, uint8_t mask)
{
*port |= mask;
}
#define set_bits_macro(port,mask) ((port) |= (mask))
int main (void)
{
set_bits_func_wrong (PORTB, 0xaa);
set_bits_func_correct (&PORTB, 0x55);
set_bits_macro (PORTB, 0xf0);
return (0);
}
The first function will generate object code which is not even close to what is intended. The major problem arises when the function is called. When the compiler sees this call, it will actually pass the value of the PORTB register (using an IN instruction), instead of passing the address of PORTB (e.g. memory mapped io addr of 0x38, io port 0x18 for the mega128). This is seen clearly when looking at the disassembly of the call:
set_bits_func_wrong (PORTB, 0xaa);
10a: 6a ea ldi r22, 0xAA ; 170
10c: 88 b3 in r24, 0x18 ; 24
10e: 0e 94 65 00 call 0xca
So, the function, once called, only sees the value of the port register and knows nothing about which port it came from. At this point, whatever object code is generated for the function by the compiler is irrelevant. The interested reader can examine the full disassembly to see that the function's body is completely fubar.
The second function shows how to pass (by reference) the memory mapped address of the io port to the function so that you can read and write to it in the function. Here's the object code generated for the function call:
set_bits_func_correct (&PORTB, 0x55);
112: 65 e5 ldi r22, 0x55 ; 85
114: 88 e3 ldi r24, 0x38 ; 56
116: 90 e0 ldi r25, 0x00 ; 0
118: 0e 94 7c 00 call 0xf8
You can clearly see that 0x0038 is correctly passed for the address of the io port. Looking at the disassembled object code for the body of the function, we can see that the function is indeed performing the operation we intended:
void
set_bits_func_correct (volatile uint8_t *port, uint8_t mask)
{
f8: fc 01 movw r30, r24
*port |= mask;
fa: 80 81 ld r24, Z
fc: 86 2b or r24, r22
fe: 80 83 st Z, r24
}
100: 08 95 ret
Notice that we are accessing the io port via the LD and ST instructions.
The port parameter must be volatile to avoid a compiler warning.
Note:
Because of the nature of the IN and OUT assembly instructions, they can not be used inside the function when passing the port in this way. Readers interested in the details should consult the Instruction Set data sheet.
Finally we come to the macro version of the operation. In this contrived example, the macro is the most efficient method with respect to both execution speed and code size:
set_bits_macro (PORTB, 0xf0);
11c: 88 b3 in r24, 0x18 ; 24
11e: 80 6f ori r24, 0xF0 ; 240
120: 88 bb out 0x18, r24 ; 24
Of course, in a real application, you might be doing a lot more in your function which uses a passed by reference io port address and thus the use of a function over a macro could save you some code space, but still at a cost of execution speed.
Care should be taken when such an indirect port access is going to one of the 16-bit IO registers where the order of write access is critical (like some timer registers). All versions of avr-gcc up to 3.3 will generate instructions that use the wrong access order in this situation (since with normal memory operands where the order doesn't matter, this sometimes yields shorter code).
See **broken link removed** for a possible workaround.
avr-gcc versions after 3.3 have been fixed in a way where this optimization will be disabled if the respective pointer variable is declared to be volatile, so the correct behaviour for 16-bit IO ports can be forced that way.
Last edited: