| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- /*
- * Copyright (C) 2001-2006 by egnite Software GmbH
- * Copyright (C) 2009 by egnite GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*
- * $Id: xmemtest.c 3597 2011-10-21 16:17:18Z haraldkipp $
- *
- * WARNING! Do not use any part of Basemon for your own applications. WARNING!
- *
- * This is not a typical application sample. It overrides parts of Nut/OS to
- * keep it running on broken hardware.
- */
- #include <stdint.h>
- #include <string.h>
- #include <stdio.h>
- #include "utils.h"
- #include "uart.h"
- #include "xmemtest.h"
- extern uint8_t GetChar(void);
- #define MERR_BAD_ADDR 1
- #define MERR_BAD_DATA 2
- #define MERR_STICKY_WRITE 3
- #define MERR_STICKY_READ 4
- #define MERR_STICKY_ALE 5
- #define MERR_STICKY_DATABUS 6
- #define MERR_STICKY_ADDRBUS 7
- #define MERR_SHORT_DATABUS 8
- #define MERR_SHORT_ADDRBUS 9
- static int merr;
- static uint8_t merr_bits;
- static void *merr_addr;
- /* PORTA: AD0..7 */
- /* PORTC: A8..15 */
- /*
- * PG0: \WR
- * PG1: \RD
- * PG2: ALE
- * PG3: TOSC2
- * PG4: TOSC1
- */
- /*!
- * \brief Disable external memory interface.
- *
- * On return, control bus signals are high and address
- * and data bus are low.
- */
- void XMemDisable(void)
- {
- #if defined (__AVR__)
- /* Disable external memory bus. */
- #if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
- cbi(XMCRA, SRE);
- #else
- cbi(MCUCR, SRE);
- #endif
- #ifdef __AVR_ENHANCED__
- /* Disable write signal. */
- sbi(PORTG, PORTG0);
- sbi(DDRG, PORTG0);
- /* Disable read signal. */
- sbi(PORTG, PORTG1);
- sbi(DDRG, PORTG1);
- /* Set ALE high, which makes latch transparent. */
- sbi(PORTG, PORTG2);
- sbi(DDRG, PORTG2);
- #endif
- /* Set latch register to zero. */
- outb(PORTA, 0);
- outb(DDRA, 0xFF);
- #ifdef __AVR_ENHANCED__
- cbi(PORTG, PORTG2);
- sbi(PORTG, PORTG2);
- #endif
- /* Set high address bus to zero. */
- outb(PORTC, 0);
- #ifdef __AVR_ENHANCED__
- outb(DDRC, 0xFF);
- #endif
- #endif /* __AVR__ */
- }
- #ifdef __AVR_ENHANCED__
- void XMemLatch(uint8_t val)
- {
- /* Port A is connected to latch inputs. */
- outb(PORTA, val);
- outb(DDRA, 0xFF);
- /* Falling edge will set the latch. */
- cbi(PORTG, PORTG2);
- }
- void MemWrite(uintptr_t addr, ureg_t data)
- {
- /* Set high address byte. */
- outb(PORTC, addr >> 8);
- /* Set low address byte. */
- outb(PORTA, (uint8_t)addr);
- /* ALE falling */
- cbi(PORTG, PORTG2);
- /* Set data byte. */
- outb(PORTC, data);
- /* Low pulse on write. */
- cbi(PORTG, PORTG0);
- cbi(PORTG, PORTG0);
- /* If ALE is high, then latch is transparent. */
- sbi(PORTG, PORTG2);
- }
- ureg_t MemRead(uintptr_t addr)
- {
- uint8_t rc;
- /* Set high address byte. */
- outb(PORTC, addr >> 8);
- /* Set low address byte. */
- outb(PORTC, (uint8_t)addr);
- /* ALE falling */
- cbi(PORTG, PORTG2);
- /* Read signal falling. */
- cbi(PORTG, PORTG1);
- /* Read data byte. */
- rc = inb(PORTC);
- /* Read signal rising. */
- sbi(PORTG, PORTG1);
- /* If ALE is high, then latch is transparent. */
- sbi(PORTG, PORTG2);
- return rc;
- }
- /*!
- * \brief Detect sticky memory bus bits and shortcuts.
- */
- int XMemTestBus(void)
- {
- uint8_t wb;
- /*
- * Disable external memory bus. This will set the control bus
- * signals high, clear the address latch and set all data and
- * address bus lines to low.
- */
- XMemDisable();
- /*
- * First check for sticky control bus signals. We switch them
- * to inputs, but they should be kept high because the pullup
- * is enabled. If they become low, something is wrong.
- */
- cbi(DDRG, PORTG0);
- if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
- merr = MERR_STICKY_WRITE;
- return -1;
- }
- sbi(DDRG, PORTG0);
- cbi(DDRG, PORTG1);
- if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
- merr = MERR_STICKY_READ;
- return -1;
- }
- sbi(DDRG, PORTG1);
- cbi(DDRG, PORTG2);
- if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
- merr = MERR_STICKY_ALE;
- return -1;
- }
- /*
- * Check the data bus for any sticky bits. Note, that ALE is
- * still low, so the latch contents (all zero) will appear on
- * the high byte address bus lines. We switch AD0..AD7 into
- * input mode, enable the pullups and expect all line kept
- * high.
- */
- outb(DDRA, 0);
- outb(PORTA, 0xFF);
- Delay(16);
- if(inb(PINA) != 0xFF) {
- merr_bits = ~inb(PINA);
- merr = MERR_STICKY_DATABUS;
- return -1;
- }
- /*
- * Do a walking bit test to find shortcuts.
- */
- for(wb = 1; wb; wb <<= 1) {
- outb(PORTA, ~wb);
- outb(DDRA, wb);
- Delay(16);
- if(inb(PINA) != (uint8_t)~wb) {
- merr = MERR_SHORT_DATABUS;
- return -1;
- }
- };
- outb(PORTA, 0);
- outb(DDRA, 0xFF);
- #ifdef __AVR_ENHANCED__
- /*
- * Checking the high address bus is easy.
- */
- outb(DDRC, 0);
- outb(PORTC, 0xFF);
- Delay(16);
- if(inb(PINC) != 0xFF) {
- merr_bits = ~inb(PINC);
- merr = MERR_STICKY_ADDRBUS;
- return -1;
- }
- for(wb = 1; wb; wb <<= 1) {
- outb(PORTC, ~wb);
- outb(DDRC, wb);
- Delay(16);
- if(inb(PINC) != (uint8_t)~wb) {
- merr = MERR_SHORT_ADDRBUS;
- return -1;
- }
- };
- outb(PORTC, 0);
- outb(DDRC, 0xFF);
- #endif
- return 0;
- }
- #endif
- /*!
- * \brief Test external SRAM.
- *
- * \return Number of bytes available.
- */
- size_t XMemTest(void)
- {
- size_t first = RAMEND + 1;
- size_t last = (size_t)-1;
- size_t addr;
- volatile uint8_t *mem;
- uint8_t wb;
- uint8_t pattern[] = { 0x00, 0xFF, 0x55, 0xAA };
- #if defined(__AVR_ENHANCED__) && !defined(__AVR_ATmega2561__)
- /*
- * Test external memory bus on ATmega128 systems.
- * Fails on the ATmega2561. Why?
- */
- if(XMemTestBus()) {
- return 0;
- }
- #endif
- /*
- * Enable external RAM.
- */
- #if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
- outb(XMCRA, _BV(SRE));
- #elif defined (__AVR__)
- outb(MCUCR, _BV(SRE));
- #endif
- /*
- * Let's see, how many kBytes we have. A simple pattern test on the
- * first bytes of each kilobyte boundary will do.
- */
- for (addr = first; addr >= first; addr += 1024) {
- mem = (uint8_t *)((addr + 1024) - sizeof(pattern));
- memcpy((void *)mem, pattern, sizeof(pattern));
- if(memcmp((void *)mem, pattern, sizeof(pattern))) {
- last = addr - 1;
- }
- /*
- * External RAM may not start at kilobyte boundary. Set the
- * address to full kilobytes after first test.
- */
- else if(addr == RAMEND + 1) {
- addr &= ~0x3FF;
- }
- }
- /*
- * Set all bits in RAM.
- */
- for (addr = first; addr >= first && addr < last; addr += 256) {
- memset((void *)addr, 0xFF, 256);
- }
- /*
- * Do an extensive test.
- */
- for (addr = first; addr >= first && addr < last; addr++) {
- mem = (uint8_t *)addr;
- /*
- * The next RAM location must still have all bits set. If not,
- * any manipulation on lower addresses may have modified this
- * one. Probably an address bus problem.
- */
- if(*mem != 0xFF) {
- merr_bits = ~*mem;
- merr_addr = (void *)mem;
- merr = MERR_BAD_ADDR;
- break;
- }
- /*
- * Do a walking bit test including all bits zero on the current
- * RAM location.
- */
- wb = 1;
- *mem = wb;
- do {
- if(*mem != wb) {
- break;
- }
- wb <<= 1;
- *mem = wb;
- } while(wb);
- /*
- * If the walking bit test hasn't finished or if not all bits
- * are cleared, then this data byte is broken.
- */
- if(wb || *mem) {
- if(wb) {
- merr_bits = *mem & ~wb;
- }
- else {
- merr_bits = *mem;
- }
- merr_addr = (void *)mem;
- merr = MERR_BAD_DATA;
- break;
- }
- }
- return last - first + 1;
- }
- /*!
- * \brief Test external banked SRAM.
- *
- * Banked memory is asumed on top of non-banked memory and the
- * start of banked memory is assumed on a 256 byte boundary.
- *
- * \return Number of banks available.
- */
- int XMemBankTest(size_t *xramsize)
- {
- volatile uint8_t *breg = (uint8_t *)((size_t)-1 & ~0xFF);
- volatile uint8_t *bmem = 0;
- size_t bsize = 16384;
- uint8_t *bend = (uint8_t *)bmem + bsize;
- uint8_t *xramend = (uint8_t *)(*xramsize + RAMEND + 1);
- volatile uint8_t *cp;
- uint8_t i;
- uint8_t j;
- /*
- * Determine the start address of banked memory. Switch to
- * bank 1 and set every 256th byte to 1. Then switch to bank 0
- * and clear every 256th byte. Next switch back to bank 1
- * and find the first location set to 1.
- */
- *(breg + 1) = 1;
- for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
- *cp = 1;
- }
- *breg = 0;
- for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
- *cp = 0;
- }
- *(breg + 1) = 1;
- for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
- if(*cp == 1) {
- bmem = cp;
- break;
- }
- }
- /*
- * No RAM location kept the value of 1. There is no banked memory.
- */
- if(bmem == 0) {
- return 0;
- }
- *xramsize = xramend - bmem;
- for(i = 1; i; i++) {
- *(breg + i) = i;
- memset((void *)bmem, i, bsize);
- for(cp = bmem; cp < bend; cp++) {
- if(*cp != i) {
- break;
- }
- }
- if(cp < bend) {
- break;
- }
- /*
- * Test if non-banked memory is intact.
- */
- for (cp = (uint8_t *)(RAMEND + 1); cp < bmem; cp += 256) {
- if(*cp) {
- break;
- }
- }
- if(cp < bmem) {
- break;
- }
- for(j = 0; j < i; j++) {
- *(breg + j) = j;
- for(cp = bmem; cp < bend; cp++) {
- if(*cp != j) {
- break;
- }
- }
- if(cp < bend) {
- break;
- }
- }
- if(j < i) {
- break;
- }
- }
- return i;
- }
- /*
- * Read/write external SRAM until key pressed.
- */
- void LoopSRAM(void)
- {
- register unsigned int pattern;
- volatile uint8_t *mem;
- uintptr_t faddr = 0xFFFF;
- puts("Check address and data bus.");
- printf_P(presskey_P);
- for (;;) {
- for (pattern = 1; pattern; pattern <<= 1) {
- if (pattern <= RAMEND)
- mem = (uint8_t *) (pattern | (RAMEND + 1));
- else
- mem = (uint8_t *) pattern;
- *mem = (uint8_t) ((pattern >> 8) | pattern);
- }
- for (pattern = 1; pattern; pattern <<= 1) {
- if (pattern <= RAMEND)
- mem = (uint8_t *) (pattern | (RAMEND + 1));
- else
- mem = (uint8_t *) pattern;
- if (*mem != (uint8_t) ((pattern >> 8) | pattern))
- faddr = (uintptr_t) mem;
- }
- Delay(5000);
- if (GetChar()) {
- printf("No RAM at 0x%04X\n", (unsigned int)faddr);
- return;
- }
- }
- }
|