TAP-AVR

   AVR-Tips

avr-ML上での役立ちそうな情報をあげてみました。


●拡張メモリ
●EEPROM
●インラインアセンブラと関数コール時のレジスタの使われ方
●gccのインラインアセンブラ
●logical line separator bug
●linker bug? or spec?
●bit MACRO
●RAMの有効活用
●avr-as,avr-ld,avr-objdumpについて
●スタートアップルーチンが2kを超えてrjmpが使えんくなったら
●ROM-printf
●ぷろぐめむ
●割り込みプログラム
●デバッグインフォをつけてコンパイル
●extent RAM
●アセンブラまでproceccer名を通す
●タイマーのデモプログラム
●MegaAVRのコンパイル
●カレントバージョンのgccのbugfix
●avr-libc20000503とbinutilsに関するバグ?ld-scriptのバグ?
●コードマップとコードサイズ


●拡張メモリ

1999/12/28

You must copy file /usr/local/avr/lib/ldscripts/avr44x4.x to home of
your project, edit line:
data (rw!x) : ORIGIN = 0x800060, LENGTH = 256
----------------------------------------------^^^

and use:
avr-ld --script changed-avr44x4.x [your options]
or
avr-gcc -Wl,--script,changed-avr44x4.x [your options]

Denis.

2000/05/28

#define SomeControlReg 0x1234

*((uint8_t *)(SomeControlRegister)) = 0x23;

The compiler will never notice that you are addressing something outside of
the defined linker SRAM area.


●EEPROM

けど、PROGMEMを使うらしい。

2000/01/06

int eeprom_var __attribute__ ((section (".eeprom")));
int eeprom_array[90] __attribute__ ((section (".eeprom")));

void boo(unsigned char *i){}

main ()
{
boo (&eeprom_array[9]);
}

For real work with data in `.eeprom' you must use special macros or
functions.

Denis.

> Could you please let me know how can I define a "register" variable
> in AVR-GCC?
>
> If you can, could you please also let me know how can I define
> an "eeprom" variable in AVR-GCC?
>
Regarding EEPROM: Avr-gcc doesn't "know" anything other than eram. That is
a hangover from it's von-neuman architecture background. I think the
simplest approach would be to declare all your EEProm variables in ASM (AVA)
and write some routines to read/write eeprom given an address. You could do
that in C or Asm. e.g.

unsigned char ReadEEprom(char *name)
{
outp(low(name), EEARL);
outp(high(name), EEARH);
outp(<The appropriate bit mask >, EECR);
return (inp(EEDR));
}

One thing to beware: if you are going to be multitasking or accessing eeprom
from an interrupt routine you need to encase the read/write routines with
CLI/STI (disable/enable interrupts) since i/o access to the eeprom isn't
atomic (three writes and a read to get at data).

インラインアセンブラへ続く

2000/05/23

Wasn't 17-May-2000, at 08:31PM, when Sergio Rodrigues said:
> From all the time I've been working with AVRGcc I never had the needs to
> put default values in the EEPROM. I was all over the documentation that
> I have and I could fin a replace for:
>
> "
> .eseg
> example_data:
> .db 89 ;'T'
> .db 111 ;'e'
> .db 117 ;'s'
> .db 32 ;' t'
> "
>
> Can anyone tell me how will i do this ?

This should do it:

uint8_t example_data __attribute__((section (".eeprom"))) = {
'T', 'e', 's', 't'
};

If you want it to be a null-terminated string (your example wasn't
null-terminated), use this:

char example_data[] __attribute__((section (".eeprom"))) = "Test";

--
Rich Neswold

efax: 1.240.536.7092
web: www.enteract.com/~rneswold/


●インラインアセンブラ

上の続きです。


To declare a global register variable:

register int foo asm ("r3");

The above is needed in *all* C source files or the compiler will crap on
your register somewhere. You can't reserve R0, R1 or R28, R29 (Y) - these
are special registers from GCC's point of view. One other thing: Just
because the compiler doesn't use the register doesn't mean that one of the
libraries won't. NB: know your libraries well or don't use the supplied
libraries if you are going to declare global register variables. There
isn't any point in declaring local register variables since that is exactly
what gcc does by default.

There is a C command line option that does this as well. You will have to
figure that one out yourself. All of this is in the GCC documentation :

Larry Barelio.

さらに、

2000/01/26

"D. Cook" wrote:

> I need to write a quick bit reversal routine. A bit tough in C, but easy in
> assembly.

Nice, actually if you'd make such for 8, 16, and 32 bits, then that would be a
nice addition to the standard library.

> Is there any documentation where I can find out the register call/usage
> conventions for avr-gcc?

Apart from the source to avr-gcc, I don't think so. You only need to look at
few files though. However, I'd encourage a different approach that could prove
more resistent to changes in avr-gcc, namely to explore the extended asm("..")
construct in GCC. Eg., you could write your function as (completely untested):

char rev8(char a)
{
char b;
asm("magic %1, %0" : "=r" (b) : "r" (a));
return b;
}

where %1 and %0 are replaced for the register holding the value of b and a. If
you need temporary registers, just declare them as temporary variables and pass
them to the asm() construct the same way. Nice, simple, and future safe.

Regards,

Tommy

2000/05/09

Look to file string-avr.h from avr-libc for asm examples.

> What chars are legal for "=char (expression)" and which for "char
> (expression)"?

Search gcc info for: "AVR family".
And read the AVR constraints description.

> What registers can i change without effect in an asm expression?

Only __tmp_reg__ (r0).

>
> I want to write two macros "SAVE_FLAGS" and
> "RESTORE_FLAGS" that save the internal state (SREG, located in memory at $5f)
> into a local variable.
>
> Could i declare it as this?
>
> #define SAVE_FLAGS(var) __asm__ __volatile__ ( \
> "in r0, $3f \n\t" \
> "st x,r0 \n\t" \
> : \
> : "x (&var)" \
> : "r0" "r26" "r27" \
> )

#include "io.h" /* You must have the avr-libc */
#define SAVE_FLAGS(var) var=inp (SREG)
#define RESTORE_FLAGS(var) outp(var,SREG);

> Another question:
> when i call assembler routines from C, how are parameters
> given/returned?

Look to avr-libc/src/ctoasm.inc

>From my mail archive:

Paulo Soares <psoares@consiste.pt> writes:

> What is the calling convention in C (avr-gcc)?

register usage

Parameters* Parameter 1 Parameter 2 Parameter 3 Parameter 4

f(p8,p8) R25 R24
f(p8,p8,p8,p8) R25 R24 R23 R22
f(p16,p16) R25:R24ー R23:R22
f(p16,p16,p16) R25:R24 R23:R22 R21:R20
f(p32,p32) R25:R24:R23:R22ー R21:R20:R19:R18
f(p32,p32,p32) R25:R24:R23:R22 R21:R20:R19:R18 R17:R16:R15:R14
f(p8,p16,p32) R25 R24:R23 R22:R21:R20:R19

return value
p8 R25:R24ーー
p16 R25:R24
p32 R25:R24:R23:R22

ー MSB left, LSB right (r25 - lower, r24 - higher, and so on)
ーー R25 is cleared

Denis.

2000/05/27

> Per CtoASM.inc it appears that a C function can trash
>
> R31, R30, R27,R26, R1 and R0 (e.g. Z, X, R0 and R1)
>
> Is this correct? I seem to recall R1 needing to be Zero'd before
> returning - or is that only in the case of interrupt handlers?

Call-used registers: r18-r27, r30-r31
Call-saved registers: r2-r17, r28-r29
Fixed registers: r0, r1

So a C function can trash any call-used registers (some can be used
for return value), and must save/restore changed call-saved registers.
Fixed registers are never allocated by gcc itself, r0 is a temporary
register that can be trashed by anything (except interrupt handlers
which save it).

Normally r1 is always zero (initialized at startup) and code generated
by avr-gcc depends on this. You can change it in asm subroutines if
necessary (gcc does it too in one place - out_movsi_mr_r; another will
be after the "mul" instruction), but then you must do "clr r1" before
calling or returning to any C code.

Interrupts save r1 too because an interrupt might happen when r1 is
non-zero (used as another temporary register as mentioned above).

Hope this helps,
Marek


●logical line separator bug

2000/01/26

> > Use `$' as a logical lines separator.
> >
> > i.e
> > #define LPMRdZpp(Rd) $\
> > LPM $\
> > MOV Rd,R0 $\
> > ADIW ZL,1
> >
> > It's work with binutils-2.9.5.0.13-avr-patch-1.1.gz
>
> No it doesnt work, because the lpm mnemonic make an error:
>
> MOV R1, R0 $ MOV R1, R1 ; this is working
>
> LPM $ MOV R0, R1 ; error

Oops. It's my bug.

Add this to binutils/gas/config/avr/tc-avr.h

#define LEX_DOLLAR 0
/* AVR port uses `$' as a logical line separator */

Denis.


●linker bug? or spec?

2000/01/09

It's a known problem. You must do:
avr-gcc avr.c -o test -Wall -Os -Xlinker -v
avr-ld --oformat=ihex test -o test.ihex

I don't know why :-( (May be this is a GNU binutils bug).

Denis.


●bit MACRO

2000/01/18

How about something like:

typedef struct flags {
unsigned int flag1:1 ;
unsigned int flag2:1 ;
unsigned int flag3:1 ;
unsigned int flag4:1 ;
} flagsT ;

flagsT myFlags ;

#define TRUE (1)
#define FALSE (0)

myFlags.flag3 = TRUE ;

if ( myFlags.flag2 || myFlags.flag4 ) {
/* go do something */
}

Regards,

-Allan


●RAMの有効活用

2000/01/20

Hallo,

in the context of RAM used for storage of constant values, how can i
find out the Resource Usage of my program. Running

hertz:~/work/projekte/linac/cps84int/avr> grep "dc.b" cps84ctl.s | wc
457 914 4816

means probably that at least 457 bytes out of 512 bytes in the 8515
are consumed for variables and constants in ram. Is the rest available
for the stack or are there other consumers of RAM.

Thanks

Uwe Bonnes

つづき。

2000/01/21

Mike Bechtold writes:
> Refer to progmem.h it shows examples also.
>
> Here are examples of stuff I've done

#include <progmem.h>

> char CompileHistory[] PROGMEM = "Compile History: ";
> char Date[] PROGMEM = __DATE__;
> char CompileTime[] PROGMEM = __TIME__;
> char Revision[] PROGMEM = "Rev 0.2";
>

Hallo Mike,

thanks for your tip. Before using these static variables, I think I
have to copy them with progmem_read_byte?

Bye

Uwe Bonnes


●avr-as,avr-ld,avr-objdumpについて

2000/01/21

> But with the binutils version, avr-objcopy produces only empty binary or
> intel hexfiles files without data:
>
> avr-gcc $ASOPT eeprom.S -o eeprom.out
> avr-objcopy -O binary eeprom.out eeprom.rom

You must use following command line:
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" -O \
binary <in-file> <out-file>

Read section `Examples of using avr-as, avr-ld, avr-objdump.' from
http://medo.fov.uni-mb.si/mapp/uTools

Denus.


●スタートアップルーチンが2kを超えてrjmpが使えんくなったら

2000/02/03

Here is my fixed startup code. これ

Place it in the avr/lib/src directory and rebuild the libs.

-- Devin
----- Original Message -----
From: Thomas P
To: AVR - Mailinglist
Sent: Monday, January 31, 2000 1:48 PM
Subject: Problem

Who can help me?

I'm working with the ATMEGA103 and the GNU-C-Compiler.

My Codesize is about 2KWords great. The Startuproutine in the compiled C-File doesn't work longer.
At the end of the startuproutine (in the ASM-File) there is a RJMP to the MAIN-Function which is more than 2KWord away.
How can I go around this problem?
How can I replace this RJMP to a normal JMP?

Thank you for answer

Tom


●ROM-printf

2000/02/04

Attached is my updates to rprintf. これ

For anyone interested, it defines printf() and rom_printf() where
rom_printf()'s format string is stored in flash.

Also, "%t" type was added for "text", strings stored in flash.

I hope someone out there finds it useful.

-- Devin


●ぷろぐめむ

2000/02/10

Hello everybody,
I wish to put an array of strings into progmem. The only solution I found is
------
PROGMEM char pcStandard[] = "Standard";
PROGMEM char pcClass[] = "Class";
PROGMEM char pcVendor[] = "Vendor";
PROGMEM char pcReserved[] = "Reserved";
char * _NAME_USB_REQUEST_TYPE[] =
{pcStandard, pcClass, pcVendor, pcReserved };
----
The more elegant and for normal memory usual way
-----
PROGMEM char * _NAME_USB_REQUEST_TYPE[] =
{ "Standard", "Class", "Vendor", "Reserved" };
----
puts just the pointers into program memory but the strings into normal
memory. Has anybody an idea, how to get the second form to work ?
Thanks
Michael Rickmann

2000/05/09

Hi,

Well... that's what happens when you are too fast!
It's right, I am missing the PROGMEM directive.

But still it doesn't seem to work!
unsigned char PROGMEM *test[4] = { "aaa","bbb","ccc","ddd" };

Regards,
-=[ Michael Kristensen ]=[ mke@nospam.dk ]=-

2000/05/09

Michael Kristensen <mke@nospam.dk> writes:

> It's right, I am missing the PROGMEM directive.
>
> But still it doesn't seem to work!

I frequently use something like this for debugging purposes:

#include <progmem.h>

void sendprgstr(prog_char *s)
{
char c;
while ((c = PRG_RDB(s++)))
SendByte(c);
}

#define DPRINT(str) sendprgstr(PSTR(str))

DPRINT("This string will be stored in program memory\n");

- Tor Ringstad -


●割り込みプログラム

2000/02/14

> I have spent several frustrating hours today trying to figure out how to
> tie into the interrupts using binutils and avr-gcc. ;)
>
> Can anyone shed some light on using interrupts with avr-gcc?

This example is for one of the Timer2 interrupts, just increments a
global variable. The signal names for the interrupts are defined in
(/usr/local/avr/include/)signal.h.

#include <io8535.h>
#include <iomacros.h>
#include <interrupt.h>
#include <signal.h>

SIGNAL (SIG_OUTPUT_COMPARE2)
{
softwareTimer++;
}

Regards
OAO


●デバッグインフォをつけてコンパイル

2000/02/16

> Hi,
>
> Is there anyway to get GCC to put the C in comments
> in the assembler output like IAR can do? I have the
> assembler output but it is fairly difficult to match up
> with the C.

You must compile your sources with debugging info (option -g).
and after linking you can run `avr-objdump -S your_linked_file'

denis


●extent RAM

2000/02/23

> I am trying to interface 32kb sram with a AT90S8515 (8MHz) but it doesn't
> work the way I want it to!
>
> I have changed the linker script line:
> data (rw!x) : ORIGIN = 0x60, LENGTH = 512
> to
> data (rw!x) : ORIGIN = 0x60, LENGTH = 32K
>
> But when I define an array i AVR GCC: buffer[1024] and dump the entire
> buffer to the serial port, the stackpointer is placed in the middle of the
> buffer. Is it possible to define the "start address" of the array, to be
in
> the beginning of the xram?
> (I would prefer to keep the SP in internal memory)
>
I had the same problem and used the linker script to reserve a stack
segment. Of course you can delete references to the miomap segement in the
example below (I used it to do memory mapped IO with some peripherals).
Place such a file into the directory of your project and link
with -Wl,--script,ex-avr85xx.x.

Regards
Michael Rickmann

これ


●アセンブラまでproceccer名を通す

2000/03/22

> > try:
> > avr-gcc -mmcu=atmega103 entry.S -c # -c = compile only (don't linking)
>
> This is basically what I've already got, but it doesn't seem to work
> (you can see the effect if you delete the ".arch" line in "entry.S".
> Actually my "Makerules" entry for .S.o in the file I've sent you is
> wrong, but it still doesn't seem to work with the corrected version
> either.

Oops. I forgot important thing - avr-gcc don't pass mcu name to
assembler. Instead avr-gcc puts `.arch xxxx' to .s file.
try:
avr-gcc -Wa,-mmcu=atmega103 entry.S -c

Denis.


●タイマーのデモプログラム

2000/04/03

The attached files are as follows. これ
led.h => LED control macros
mytypes.h => my own defined types
tmr0.c tmr0.h => timer0 overflow ISP
main.c

This demo is flushing LED every one second.
The period is controlled by combination of clock prescale value, TCNT0 value
and TMR0_OneSec variable.
You can modify constant at line 50 in "tmr0.c" simply to change flushing period.
Included files were compiled using win32 port avrgcc(ver. 2.95.2 19991024) by Volker Oth.

Good-luck Thomas !

Woo-Hyun Kim.

Sorry!
I forgot sei();
Modify main.c as follow.

int main(void)
{
LED0_Init();
TMR0_Init();
sei(); // Set global interrupt enable mask

while (1)
{
// background task
}
}

Woo-Hyun Kim


●MegaAVRのコンパイル

2000/04/06

% avr-gcc -mmcu=at90s2313 -Wa,-ahlms=gcctest1.lst
-Wl,-Map=gcctest1.map,--cref -o gcctest1 gcctest1.c
% avr-objcopy -O ihex gcctest1 gcctest1.ihex

makes a workable program. But it fails for atmega103:

% avr-gcc -mmcu=atmega103 -Wa,-ahlms=gcctest1.lst
-Wl,-Map=gcctest1.map,--cref -o gcctest1 gcctest1.c
/usr/local/avr/bin/ld: cannot find -lgcc-mega

答えは、

Do a

ln -s libc-mega.a libgcc-mega.a

then it works (at least on my computer).

Regards
Georg


●カレントバージョンのgccのbugfix

2000/04/19

Hi,

the patch below is necessary for the current gcc CVS tree to build
(and not try to build target-libiberty, which fails) for the avr
target (previous snapshot I tried was 20000403 and it was fine).

I'm sending this as Denis is very busy now, I hope he doesn't mind.
(as you can see, the changes are trivial, but I'm not a real gcc
hacker, so please correct if anything is wrong...)

Thanks,
Marek

--- avr.c.orig	Tue Mar 21 07:45:57 2000
+++ egcs/gcc/config/avr/avr.c	Wed Apr 19 13:01:35 2000
@@ -20,8 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
-#include <stdio.h>
-#include <string.h>
+#include "system.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
--- configure.in.orig	Fri Apr  7 14:02:36 2000
+++ egcs/configure.in	Wed Apr 19 13:40:21 2000
@@ -630,6 +630,9 @@
            target_configdirs="${target_configdirs} target-bsp target-libstub target-cygmon"
     fi
     ;;
+  avr-*-*)
+    noconfigdirs="$noconfigdirs target-libiberty"
+    ;;
   c4x-*-*)
     noconfigdirs="$noconfigdirs target-libg++ ${libstdcxx_version}  target-librx target-libgloss"
     ;;


●avr-libc20000503とbinutilsに関するバグ?ld-scriptのバグ?

2000/05/15

I have recently downloaded the avr patches to gcc, binutils, and gdb and
compiled them. I also got the avr-libc-20000503. Many thanks to the people
that ported all of these to the AVR!

I did find a few problems while playing around with them. I have written my
solutions, but if there are better ones, let me know. The first problem was
that avr-as choked on some files in avr-libc. I tracked it down to a bug in
the lexer, not related to the patch. Here is the patch for that problem (I
also reported it to FSF):

--- binutils-2.9.5.0.13/gas/app.c       Mon Jul 19 09:46:51 1999
+++ binutils-2.9.5.0.13.save/gas/app.c  Thu May 11 20:31:28 2000
@@ -989,7 +989,7 @@
 
         case LEX_IS_LINE_SEPARATOR:
          state = 0;
-         PUT (ch);
+         PUT ('\n');
          break;
 #ifdef TC_V850

Next I tried compiling some test programs and found a problem with the
linker scripts that were installed by avr-ld in /opt/avr/avr/lib/ldscripts.
(I made my base install /opt/avr.)
They didn't include some code from gcrt1 due to section naming. I fixed this
one by copying the linker script and adding one line:

.text :
  {
    *(.init)
/* ------------------------ */
/* here is the line I added */
    *(.text.gcrt1*)
/* ------------------------ */
    *(.progmem.gcc*)
    *(.progmem*)
    . = ALIGN(2);
    *(.text)
    . = ALIGN(2);
    *(.text.*)
    . = ALIGN(2);
    *(.fini)
    _etext = . ; 
   } > text

I had to add the appropriate gcrt1-xxxx.o file to the link line as well. The
linker wasn't picking up any of them. I don't see how it would select the
proper one either, based on the machine options. There are more machines
than linker options.

--
Greg Green
e-mail: gpgreen@olywa.net
http://www.olywa.net/gpgreen/


●コードマップとコードサイズ

2000/05/09

Hi all !

By using avr-size utility, you can know the size of used ram and rom of your project.
text is used rom size, data+bss is used ram size.
The following example assumes that the project name is main and
the project contains uart.c, utils.c and timer0.c files.

$ avr-size uart.o timer0.o utils.0 main.o main.elf
text data bss dec hex filename
636 0 176 812 32c uart.o
92 0 2 94 5e timer0.o
1154 12 0 1166 48e utils.o
62 0 0 62 3e main.o
2736 12 216 2964 b94 main.elf

In my project total used rom and ram size is 2736 and 228 bytes repectively.
Use "--format=sysv" options for more details.
Default "--format" is berkely.

$ avr-size --format=sysv uart.o timer0.o utils.0 main.o main.elf
uart.o :
section size addr
.text 636 0
.data 0 0
.bss 176 0
.stab 3204 0
.stabstr 2996 0
Total 7012

Regards.

Woo-Hyun Kim 2000/05/09.



return