Hi, I have an Atmega 640. I want to interface SRAM of more than 64 kB and then access the external SRAM in "pages" of 64kB. The problem I am encountering is the 8kB internal SRAM. It looks like only 56kB is available i.e. 0x2200 to 0xFFFF. I can easily interface a 32kB by using the 0x8000 logic (one address line is dont care A15). I just don't know how to bypass the 8kB!! The datasheet does say something on using *ALL* 64kB locations of external memory but I couldn't understand what it was saying. It says something about masking higher address bits to zero...setting
Port C to output 0x00, and releasing the most significant bits for normal Port Pin
operation. Please someone make me understand what the datasheet says!
External SRAM and 8kb problem
What it's saying is that when you address 0x0000-0x21FF, you won't actually get the uC to address the external memory. Instead, it will be mapped to internal. So if you want to access the internal memory on addresses that low, you need to release the PORTC bits (at least the first one or two) and control them manually. You still won't be able to have easily accessible pages of more than 56k, as the lower bit will still reference internal.
What you could do is split the ram into pages of 32k (or bigger if you like, just more math). For example, you have the address 0x8000-0xFFFF which is your 32k page range. Then you release the top 1 bit of the PORTC register and force PORTC to output 0x00 (see the example code in the datasheet, but set XMCRB = 1 << XMM0) for the first page, and the address 0x8000 will actually be 0x0000 since PORTC will be outputting 0AAAAAAA where 0 is the 0's you manually wrote and A is the address bits (as you released the top one) from the 0x8000-0xFFFF. Then for the second page, you set PORTC to 0x80.
If you want to address more than 64k, you can as well assign A16+ to another port and control the pages by setting PORTC[15] and the other port's pins as necessary.
Let me know if this still doesn't make sense and I'll clarify more.
Thanks a lot for replying. I didn't understand your post in it's entirety but what I could gather from your post is that we are referencing the entire 64kB external memory as two 32 kB pages. To bypass the 8kB internal SRAM we are writing 0x8000 on the address lines as 32kB requires only (2^5x2^10=32kB) 15 address lines. What I don't understand is how to access the first 32kB page i.e. 0x0000-0x7fff?? Have I understood this correctly? Can you please clarify this further. Thanks again!!
The only piece you missed is that we released the top (A15) line of portc to be a gpio pin and manually set it to 0. Doing so makes a write to 0x8000 fool the avr into accessing the external sram, but will actually result in 0x0000 being put on the address lines, as A15 is being controlled manually and forced to 0. Thus 0x8000-0xFFFF actually writes to 0x0000-0x7FFF when portc is written to 0x00.
To address 0x8000-0xFFFF on the chip, again write to 0x8000-0xFFFF but address page 2 by setting portc to 0x80 (or as well can set it to 0xFF since we only released the top bit to gpio and the other bits don't have any effect as they are still controlled by the sram controller).
Alternatively, forget portc[7] altogether and just put, for example, portb[0-7] on A15-A22 or as many as you have and you can address more than 64k memory in 32k pages by page number by setting portb to 0-FF to address the 256 pages.
So to summarize we release the A15 line to enable the access to the external RAM in 32kB pages. The A15 line we control manually and to access the 1st 32kB page we write 0x0000 to PORTC and to PORTA with the SRE bit enabled in the XMEMCRA register. To disable the A15 line write XMCRB = 1 << XMM0.
I didn't understand two things:-
1) To access the 2nd page we always have to set portc to 0x8000, how can we set it to 0xff and yet get 32kB?
2) By disabling the A15 line how can we hoodwink the avr and not write to the internal SRAM??
So to summarize we release the A15 line to enable the access to the external RAM in 32kB pages. The A15 line we control manually and to access the 1st 32kB page we write 0x0000 to PORTC and to PORTA with the SRE bit enabled in the XMEMCRA register. To disable the A15 line write XMCRB = 1 << XMM0.
I didn't understand two things:-
1) To access the 2nd page we always have to set portc to 0x8000, how can we set it to 0xff and yet get 32kB?
2) By disabling the A15 line how can we hoodwink the avr and not write to the internal SRAM??
Thanks again!!
The avr thinks you're writing to 0x8000, which is an external address. But since you yank control of a15 away from it, what really ends up on that pin is up to you. If you set it to 0, writing to 8000 really writes to 0000. If you set it to 1, writing to 8000 actually writes to 8000.
To answer your first question, writing portc to 0x80 or 0xFF does the same thing. You only released the top bit to gpio so writing the other 7 has mo effect. Writing 0x85 or 0xC2 would as well just set the top pin and do nothing to the rest.
It's true as you said that the A15 is user controllable and setting the A15 bit accesses the 2nd 32kB page but (pardon my stupidity :) ) how will any value other than 8000 access the full 32kB range? The 2nd 32kB page maps from 8000 to ffff, and if you write FF to port C then it will access only the last 256 locations of the 2nd 32kB page. Is this correct?
Edit:
So that also means that the A15 line will have to be permanently released??
This program is taken from the datasheet, please can anybody explain it to me??
; OFFSET is defined to 0x4000 to ensure ; external memory access ; Configure Port C (address high byte) to ; output 0x00 when the pins are released ; for normal Port Pin operation ldi r16, 0xFF out DDRC, r16 ldi r16, 0x00 out PORTC, r16 ; release PC7:6 ldi r16, (1<<XMM1) sts XMCRB, r16 ; write 0xAA to address 0x0001 of external ; memory ldi r16, 0xaa sts 0x0001+OFFSET, r16 ; re-enable PC7:6 for external memory ldi r16, (0<<XMM1) sts XMCRB, r16 ; store 0x55 to address (OFFSET + 1) of ; external memory ldi r16, 0x55 sts 0x0001+OFFSET, r16
I think this whole thread is about using the external 64K ram on the EXTERNAL MEMORY BUS of an avr? Where the ALE and RD and WR pins are asserted by the AVR and the hi address is latched into an octal 74AHC373? Or this a special tricky manual addition of an external ram using port pins to manipulate the external ram address lines? And twiddling another port as a bidirectional data port? Fist way uses the hardware in the AVR. Faster. More reliable. Downside: you need to buy an extra part that cost $1.
The External Memory (EM) peripheral performs addressing with two address bytes. A0-A15. Always.
But the EM circuitry does not drive external address pins if uC is accessing something in the 0x0000-0x21FF range.
sts 0x21FF, r0 ;no activity on the EM bus sts 0x2200,r0 ;A0-A8 were low, A9 is high ..... and A14 with A15 low
Neither EM drives external higher address pins if you disable/override PORTC pins' drive (XMMn). Lets imagine your memory is 256 bytes and with XMM = 0b111 the EM interface will not bang A8-A15 pins, even when the address indicates that:
sts 0x0000,r0 ;no address lines are driven because that is an internal address sts 0x0001,r0 ; same as above ... sts 0x21FF,r0 ; same as above sts 0x2200,r0 ; PORTC is not connected to MB so only A0-A7 lines are driven (to 0x00) sts 0x2201,r0 ; PORTC is ... are driven (to 0x01) ... sts 0x22FF,r0 ; PORTC is ... are driven (to 0xFF) sts 0x2300,r0 ;PORTC is ... are driven (to 0x00) ... sts 0xFFFF,r0 ; PORTC is ... are driven (to 0xFF)
You can ignore the 0xFF bit for PORTC, that was just to further illustrate that you're only changing the most significant bit. Consider this:
With PORTC = 0x00 you get page 0 or the first 32k Address written to Real address on bus HEX BINARY BINARY HEX VALUE 0x8000 10000000 00000000 0x0000 0 0x8001 10000001 00000001 0x0001 1 ... 0xFFFE 11111110 01111110 0x7FFE 32766 0xFFFF 11111111 01111111 0x7FFF 32767
You can see that, because you've released PORTC[7] from the address function and set it manually to 0, you force the most sig bit to be 0 and force the writing to 0x0000-0x7FFF.
Then:
With PORTC = 0x80 you get page 1 or 32-64k Address written to Real address on bus HEX BINARY BINARY HEX VALUE 0x8000 10000000 10000000 0x8000 32768 0x8001 10000001 10000001 0x8001 32769 ... 0xFFFE 11111110 11111110 0xFFFE 65534 0xFFFF 11111111 11111111 0xFFFF 65535
You can extend this using another set of GPIO pins connected to A16+ to use a larger memory chip and get as many pages as you have GPIO to control.
You just have to be sure to set the page before performing the 0x8000-0xFFFF writes.
Not entirely sure what Bob recommends the 373 chip for, but to be honest I'm not very experienced in this area, so maybe he can elaborate.
The program you pasted is essentially doing exactly what I'm saying, with the exception that it releases PORTC[7:6] instead of just 7 (writes to XMM1 instead of XMM0) and writes to 0x4000 instead of 0x8000.
Basically change XMM1 to XMM0 and change OFFSET to 0x8000 and you get the situation I suggested.
I think I understood what you people mean. When you disable the most significant bit aka A15 the external memory interface doesn't drive the pin to any value, it acts as a normal I/O pin and then becomes user defined. Hence even if you write 0x8000 or 0xFFFF the last bit becomes 0 or 1 depending upon the user. To force the AVR to assert the RD and WR strobe we have to access memory locations above 0x21FF and hence we use the offset as 0x8000 hoodwinking the avr into believing that we are accessing the external ram at locations 0x8000 but in reality we may access the 0x8000 or 0x0000 depending on the A15 bit. Is this right? It seems all too clear now!!! YES!! I understood the concept :) :) Thanks a zillion clpalmer and many thanks to bobgardner and Brutte!!!!
And here is another tweak:
Parallel SRAM memories have a nice property these do not care at what sequence you access the data:
sts 0x8000,r0 sts 0x8001,r0
This takes exactly same amount of time as:
sts 0xDead,r0 sts 0xBeef,r0
So it really does not matter if you connect address bus with uC for example in sequence:
- A0 line of ATMega to a0 line of SRAM
A1 line of ATMega to a1 line of SRAM
...
A15 line of ATMega to a15 line of SRAM
- A0 line of ATMega to a4 line of SRAM
A1 line of ATMega to a15 line of SRAM
...
A15 line of ATMega to a9 line of SRAM
Same rule applies to data lines. You can interchange them as you like.
What I wanted to say is that SRAM layout on PCB is exceptionally easy (when compared to SDRAMs, DDRs or flash) as there are few constraints involved.