Read / write a byte to NON-Register memory

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

I have a decent handle on registers and using them. I know R0 -R31 are special memory places optimized for math, logic and so on.  I wish to write to a byte some place some where as a "scratch pad" but not use an register.  Can I just read / write to 0x32, 0x33 and so on? is there a limit or restriction or a preferred area where I can muck around and not have to use register r0 - r31?

 

Thank you in advance.

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you ever heard of RAM? We don't know which chip you are using but some newer chips have also simple "scratchpad registers" or GP registers.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John : yes I have heard of RAM  LOL  

 

328P is my chip.  I know there are 3 different kinds on it. I guess my question was can i just write / read to 0x37 say or will I be overwriting some critical part of memory??

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Look at the datasheet and see where RAM starts and ends in the M328.  I can tell you but then it will not be fun for you. wink

 

What language are you using for programming? If C then simply use a  variable "scratchpad", if using assembler then you can reserve 1 or more memory locations for your scratchpad at particular address(es).

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Memory addresses above 32 have limits on which instructions can be used for access.  The LD (load) and ST (store) instructions can access anywhere in the 64k address space.

IN and OUT instructions can access locations 32-95 (the 32 "low" SFRs) (in less time and space than LD/ST)  A variety of special IO instructions like SBI and CBI (set/clear bit in IO register) can access the SFRs in the 32 to 95 range (64 "normal" SFRs.)  There are also some additional "extended" SFRs that are only accessible by LD/ST (as if they were RAM.)

The limitations are based on the number of bits reserved in the instruction to pick the location - 4 or 5 bits for CPU registers, 5 or 6 bits for SFR instructions, 16bits (or indirect via a register pair) for LD/ST...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Depending on your assembler, you can use things like .byte to give a name to a memory location.

 

So long as you use RAM that is outside of the portion where IO Registers are mapped AND that is outside of the part used by the stack, then YOU and only you have absolute control over what is written to any RAM location (in assembler). In the Mega328 Spec Sheet, check the chapter on Memory, then 8.3 SRAM Data Memory, and you will find a diagram that shows the region where IO Registers are mapped into SRAM space. I would start at 0x0100 and work up from there. Above 0x0100, it is totally you and the stack (which is at the top and works down).

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you.. It was not clear to me where the "scratch pad" or "playground" that was safe to mess around was. I know 0x00 to 0x31 are R0 to R31 but I was not sure  how much above 0x32 this "free play" are extended.  I am concerned I may access say 0x95 and damage some program memory or the like.

 

So... I am just trying to find out where the "sand box" is where I can read / write stuff with out blowing up my program.

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In one of your other threads on this:

 

awneil wrote:
 people have been programming AVRs in assembler for decades - so there is no shortage of books & tutorials on the subject

 

eg, https://www.avrfreaks.net/forum/books-atmel-avr-assembler

 

http://www.lmgtfy.com?q=AVR+assmebler+book

 

clawson wrote:

Really good Asm code comes from using intricate CPU knowledge 

 

 

You really need to get some good references, and settle down to some serious study - rather than just throwing random questions around.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jim:

 

 

.BYTE !!   Why the heck didn't I think of that!  That would allocate a byte (or more) that i can use safely all day long!  I will read up as much as I can on the memory allocation regime to learn, but for now I think a simple .BYTE will suffice.

 

Thank you everyone!

 

 

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR_Beginner wrote:
but I was not sure  how much above 0x32 this "free play" are extended

You need to consult the data sheet.

 

Apart from the registers being mapped into some of the address space, then the whole RAM is yours to use as you wish. You've chosen to program in assembler (still a mystery to me.. ;-) ) so you are in control - for better or for worse.

 

AVR_Beginner wrote:
I am concerned I may access say 0x95 and damage some program memory or the like.

You can't damage the program flash memory contents. The instructions accessing RAM can not access the flash memory. There are special instructions accessing flash memory (LPM, SPM) and as long as you're not explicitly writing to flash your nothing your code does can alter the flash contents.

 

 

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to be clear that .byte simply allocates the next byte from DSEG and like CSEG and ESEG each has a default .org address. In the case of 328p the DSEG starts at 0x0100 (which I presume you now know after following the advice above about checking the datasheet)

 

Last Edited: Sun. Dec 3, 2017 - 02:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Allocating a byte with .byte DOES NOT protect that location. Anything can alter that location, if told to.

 

The assembler might or might not complain if you .byte twice on the same memory location. It might or might not complain about two .bytes with the same name. It is still up to you to do it "right". That is part of the "cost" of using assembler. It makes it really easy to shoot yourself in the foot.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Everyone:  Thank you... lots more for me to learn ..

 

Jim:  Yes, I am aware of the risks. But my understanding is that is part of ASM... the world is open to you but you have to be very careful. 

 

At this juncture I am making simple little programs and gettting results.  As I experiment more and read more, I am sure what i can do will grow in complexity... I have to be careful.  But for now I have some small victories :-)

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR_Beginner wrote:
Thank you.. It was not clear to me where the "scratch pad" or "playground" that was safe to mess around was. I know 0x00 to 0x31 are R0 to R31 but I was not sure how much above 0x32 this "free play" are extended. I am concerned I may access say 0x95 and damage some program memory or the like.

Have you actually >>looked<< at the Memory chapter(s) in the datasheet?!?  Aren't there figures and charts and discussion about "memory map"?

 

Most of us won't write a program with "hard addresses", but rather will declare a variable and let the toolchain sort it out.

 

The short answer to your question is that you will be indeed messing up; I/O space with your given numbers.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Most of us won't write a program with "hard addresses", but rather will declare a variable and let the toolchain sort it out.

 

Yes... I realize that now.  It appears to be simpler and safer to just declare a .BYTE and let the tool chain decide what is best... the caveot is the assumption the tool chain does this well. 

I am a new AVR programmer. I am learning alone out of books, the Internet, etc. Please excuse me if I ask simple questions. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to be clear that .byte simply allocates the next byte from DSEG and like CSEG and ESEG each has a default .org address.

 Note that CSEG, etc, and .org are Atmel Assembler concepts.  IIRC, AVR_Beginner is using the gnu assembler (via Arduino), so the actual terms will be different.  (.text, .data, .section, .lcomm)

Also note that in "pure" assembler, there's essentially no such thing as "initialized" RAM data.  If you have a C statement like "byte  x =123;" or put ".byte 123" in the .data section of an gnu-assembly-language program, the compiler will allocate a RAM address, but put the "123" value into a segment of flash memory, which will get copied to RAM during the C startup code.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
Note that CSEG, etc, and .org are Atmel Assembler concepts. IIRC, AVR_Beginner is using the gnu assembler (via Arduino), so the actual terms will be different. (.text, .data, .section, .lcomm)
Ah yes, I'd forgotten about his "odd" choice of assembler. In which case the use of .byte (for RAM vars) likely needs to be preceded in avr-as with ".data". For an example see what the C compiler does with something like:

#include <avr/io.h>
#include <avr/eeprom.h>

uint8_t a,b,c,d,j;
int n = 12345;
char ch = 'A';
int e EEMEM = 456;

int main(void) {
}

this leads to:

.global e
        .section        .eeprom,"aw",@progbits
        .type   e, @object
        .size   e, 2
e:
        .word   456
.global ch
        .data
        .type   ch, @object
        .size   ch, 1
ch:
        .byte   65
.global n
        .type   n, @object
        .size   n, 2
n:
        .word   12345
        .comm   j,1,1
        .comm   d,1,1
        .comm   c,1,1
        .comm   b,1,1
        .comm   a,1,1

Notice how 'n' and 'ch' for example are assigned to the ".data" section and instantiated as ".word" or ".byte" (followed by initial value). A variable in EEMEM is assigned to ".section .eeprom" while BSS variables are actually crated by .comm which is not preceded by a section identifier as the .comm directive itself assigns them to the "COMMON" section.

 

In the linker script there is:

  .data          :
  {
     PROVIDE (__data_start = .) ;
    *(.data)
     *(.data*)
    *(.rodata)  /* We need to include .rodata here if gcc is used */
     *(.rodata*) /* with -fdata-sections.  */
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
     _edata = . ;
     PROVIDE (__data_end = .) ;
  }  > data AT> text
  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
  {
     PROVIDE (__bss_start = .) ;
    *(.bss)
     *(.bss*)
    *(COMMON)
     PROVIDE (__bss_end = .) ;
  }  > data
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);

So the load order in RAM (which is where linker section "data" is placed) will be .data variables, then .bss variable and then COMMON variables within the .bss section.

 

You can see that in the .map file:

.data           0x00800060        0x4 load address 0x0000009c
                0x00800060                PROVIDE (__data_start, .)
 *(.data)
 .data          0x00800060        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr5/crtatmega16.o
 .data          0x00800060        0x3 avr.o
                0x00800060                ch
                0x00800061                n
 .data          0x00800063        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_exit.o)
 .data          0x00800063        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_copy_data.o)
 .data          0x00800063        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_clear_bss.o)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x00800064                . = ALIGN (0x2)
 *fill*         0x00800063        0x1
                0x00800064                _edata = .
                0x00800064                PROVIDE (__data_end, .)

.bss            0x00800064        0x5
                0x00800064                PROVIDE (__bss_start, .)
 *(.bss)
 .bss           0x00800064        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr5/crtatmega16.o
 .bss           0x00800064        0x0 avr.o
 .bss           0x00800064        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_exit.o)
 .bss           0x00800064        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_copy_data.o)
 .bss           0x00800064        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_clear_bss.o)
 *(.bss*)
 *(COMMON)
 COMMON         0x00800064        0x5 avr.o
                0x00800064                b
                0x00800065                j
                0x00800066                c
                0x00800067                d
                0x00800068                a
                0x00800069                PROVIDE (__bss_end, .)
                0x0000009c                __data_load_start = LOADADDR (.data)
                0x000000a0                __data_load_end = (__data_load_start + SIZEOF (.data))

Note that a strange peculiarity of GCC is that to convert Harvard to Von Neumann it offsets the start of RAM data by 0x800000 so for the mega16 I just built this for the variables actually start at 0x0060 in the RAM of the AVR. If I had built for 328P the addresses would have been:

.data           0x00800100        0x4 load address 0x000000b0
                0x00800100                PROVIDE (__data_start, .)
 *(.data)
 .data          0x00800100        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr5/crtatmega328p.o
 .data          0x00800100        0x3 avr.o
                0x00800100                ch
                0x00800101                n
 .data          0x00800103        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_exit.o)
 .data          0x00800103        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_copy_data.o)
 .data          0x00800103        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_clear_bss.o)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x00800104                . = ALIGN (0x2)
 *fill*         0x00800103        0x1
                0x00800104                _edata = .
                0x00800104                PROVIDE (__data_end, .)

.bss            0x00800104        0x5
                0x00800104                PROVIDE (__bss_start, .)
 *(.bss)
 .bss           0x00800104        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/../../../../avr/lib/avr5/crtatmega328p.o
 .bss           0x00800104        0x0 avr.o
 .bss           0x00800104        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_exit.o)
 .bss           0x00800104        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_copy_data.o)
 .bss           0x00800104        0x0 c:/sysgcc/avr/bin/../lib/gcc/avr/5.3.0/avr5\libgcc.a(_clear_bss.o)
 *(.bss*)
 *(COMMON)
 COMMON         0x00800104        0x5 avr.o
                0x00800104                b
                0x00800105                j
                0x00800106                c
                0x00800107                d
                0x00800108                a

The actual placement of the "data" section (that holds .data, .bss etc) is dictated by the linker script when it does:

OUTPUT_ARCH(avr:5)
MEMORY
{
  text   (rx)   : ORIGIN = 0, LENGTH = 128K
  data   (rw!x) : ORIGIN = 0x800060, LENGTH = 0xffa0
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}

that one is for mega16, the one for mega328p is:

OUTPUT_ARCH(avr:51)
MEMORY
{
  text   (rx)   : ORIGIN = 0, LENGTH = 128K
  data   (rw!x) : ORIGIN = 0x800100, LENGTH = 0xff00
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}

Because avr-as (and avr-ld) form a linking assembler all this stuff is considerably more complex than in the case of the Atmel assembler which has the much simpler concept of just 3 location counters in CSEG, DSEG and ESEG (code, data and EEPROM).

Last Edited: Mon. Dec 4, 2017 - 09:49 AM