xmemtest.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*
  2. * Copyright (C) 2001-2006 by egnite Software GmbH
  3. * Copyright (C) 2009 by egnite GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Id: xmemtest.c 3597 2011-10-21 16:17:18Z haraldkipp $
  37. *
  38. * WARNING! Do not use any part of Basemon for your own applications. WARNING!
  39. *
  40. * This is not a typical application sample. It overrides parts of Nut/OS to
  41. * keep it running on broken hardware.
  42. */
  43. #include <stdint.h>
  44. #include <string.h>
  45. #include <stdio.h>
  46. #include "utils.h"
  47. #include "uart.h"
  48. #include "xmemtest.h"
  49. extern uint8_t GetChar(void);
  50. #define MERR_BAD_ADDR 1
  51. #define MERR_BAD_DATA 2
  52. #define MERR_STICKY_WRITE 3
  53. #define MERR_STICKY_READ 4
  54. #define MERR_STICKY_ALE 5
  55. #define MERR_STICKY_DATABUS 6
  56. #define MERR_STICKY_ADDRBUS 7
  57. #define MERR_SHORT_DATABUS 8
  58. #define MERR_SHORT_ADDRBUS 9
  59. static int merr;
  60. static uint8_t merr_bits;
  61. static void *merr_addr;
  62. /* PORTA: AD0..7 */
  63. /* PORTC: A8..15 */
  64. /*
  65. * PG0: \WR
  66. * PG1: \RD
  67. * PG2: ALE
  68. * PG3: TOSC2
  69. * PG4: TOSC1
  70. */
  71. /*!
  72. * \brief Disable external memory interface.
  73. *
  74. * On return, control bus signals are high and address
  75. * and data bus are low.
  76. */
  77. void XMemDisable(void)
  78. {
  79. #if defined (__AVR__)
  80. /* Disable external memory bus. */
  81. #if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
  82. cbi(XMCRA, SRE);
  83. #else
  84. cbi(MCUCR, SRE);
  85. #endif
  86. #ifdef __AVR_ENHANCED__
  87. /* Disable write signal. */
  88. sbi(PORTG, PORTG0);
  89. sbi(DDRG, PORTG0);
  90. /* Disable read signal. */
  91. sbi(PORTG, PORTG1);
  92. sbi(DDRG, PORTG1);
  93. /* Set ALE high, which makes latch transparent. */
  94. sbi(PORTG, PORTG2);
  95. sbi(DDRG, PORTG2);
  96. #endif
  97. /* Set latch register to zero. */
  98. outb(PORTA, 0);
  99. outb(DDRA, 0xFF);
  100. #ifdef __AVR_ENHANCED__
  101. cbi(PORTG, PORTG2);
  102. sbi(PORTG, PORTG2);
  103. #endif
  104. /* Set high address bus to zero. */
  105. outb(PORTC, 0);
  106. #ifdef __AVR_ENHANCED__
  107. outb(DDRC, 0xFF);
  108. #endif
  109. #endif /* __AVR__ */
  110. }
  111. #ifdef __AVR_ENHANCED__
  112. void XMemLatch(uint8_t val)
  113. {
  114. /* Port A is connected to latch inputs. */
  115. outb(PORTA, val);
  116. outb(DDRA, 0xFF);
  117. /* Falling edge will set the latch. */
  118. cbi(PORTG, PORTG2);
  119. }
  120. void MemWrite(uintptr_t addr, ureg_t data)
  121. {
  122. /* Set high address byte. */
  123. outb(PORTC, addr >> 8);
  124. /* Set low address byte. */
  125. outb(PORTA, (uint8_t)addr);
  126. /* ALE falling */
  127. cbi(PORTG, PORTG2);
  128. /* Set data byte. */
  129. outb(PORTC, data);
  130. /* Low pulse on write. */
  131. cbi(PORTG, PORTG0);
  132. cbi(PORTG, PORTG0);
  133. /* If ALE is high, then latch is transparent. */
  134. sbi(PORTG, PORTG2);
  135. }
  136. ureg_t MemRead(uintptr_t addr)
  137. {
  138. uint8_t rc;
  139. /* Set high address byte. */
  140. outb(PORTC, addr >> 8);
  141. /* Set low address byte. */
  142. outb(PORTC, (uint8_t)addr);
  143. /* ALE falling */
  144. cbi(PORTG, PORTG2);
  145. /* Read signal falling. */
  146. cbi(PORTG, PORTG1);
  147. /* Read data byte. */
  148. rc = inb(PORTC);
  149. /* Read signal rising. */
  150. sbi(PORTG, PORTG1);
  151. /* If ALE is high, then latch is transparent. */
  152. sbi(PORTG, PORTG2);
  153. return rc;
  154. }
  155. /*!
  156. * \brief Detect sticky memory bus bits and shortcuts.
  157. */
  158. int XMemTestBus(void)
  159. {
  160. uint8_t wb;
  161. /*
  162. * Disable external memory bus. This will set the control bus
  163. * signals high, clear the address latch and set all data and
  164. * address bus lines to low.
  165. */
  166. XMemDisable();
  167. /*
  168. * First check for sticky control bus signals. We switch them
  169. * to inputs, but they should be kept high because the pullup
  170. * is enabled. If they become low, something is wrong.
  171. */
  172. cbi(DDRG, PORTG0);
  173. if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
  174. merr = MERR_STICKY_WRITE;
  175. return -1;
  176. }
  177. sbi(DDRG, PORTG0);
  178. cbi(DDRG, PORTG1);
  179. if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
  180. merr = MERR_STICKY_READ;
  181. return -1;
  182. }
  183. sbi(DDRG, PORTG1);
  184. cbi(DDRG, PORTG2);
  185. if((inb(PING) & _BV(PORTG0)) != _BV(PORTG0)) {
  186. merr = MERR_STICKY_ALE;
  187. return -1;
  188. }
  189. /*
  190. * Check the data bus for any sticky bits. Note, that ALE is
  191. * still low, so the latch contents (all zero) will appear on
  192. * the high byte address bus lines. We switch AD0..AD7 into
  193. * input mode, enable the pullups and expect all line kept
  194. * high.
  195. */
  196. outb(DDRA, 0);
  197. outb(PORTA, 0xFF);
  198. Delay(16);
  199. if(inb(PINA) != 0xFF) {
  200. merr_bits = ~inb(PINA);
  201. merr = MERR_STICKY_DATABUS;
  202. return -1;
  203. }
  204. /*
  205. * Do a walking bit test to find shortcuts.
  206. */
  207. for(wb = 1; wb; wb <<= 1) {
  208. outb(PORTA, ~wb);
  209. outb(DDRA, wb);
  210. Delay(16);
  211. if(inb(PINA) != (uint8_t)~wb) {
  212. merr = MERR_SHORT_DATABUS;
  213. return -1;
  214. }
  215. };
  216. outb(PORTA, 0);
  217. outb(DDRA, 0xFF);
  218. #ifdef __AVR_ENHANCED__
  219. /*
  220. * Checking the high address bus is easy.
  221. */
  222. outb(DDRC, 0);
  223. outb(PORTC, 0xFF);
  224. Delay(16);
  225. if(inb(PINC) != 0xFF) {
  226. merr_bits = ~inb(PINC);
  227. merr = MERR_STICKY_ADDRBUS;
  228. return -1;
  229. }
  230. for(wb = 1; wb; wb <<= 1) {
  231. outb(PORTC, ~wb);
  232. outb(DDRC, wb);
  233. Delay(16);
  234. if(inb(PINC) != (uint8_t)~wb) {
  235. merr = MERR_SHORT_ADDRBUS;
  236. return -1;
  237. }
  238. };
  239. outb(PORTC, 0);
  240. outb(DDRC, 0xFF);
  241. #endif
  242. return 0;
  243. }
  244. #endif
  245. /*!
  246. * \brief Test external SRAM.
  247. *
  248. * \return Number of bytes available.
  249. */
  250. size_t XMemTest(void)
  251. {
  252. size_t first = RAMEND + 1;
  253. size_t last = (size_t)-1;
  254. size_t addr;
  255. volatile uint8_t *mem;
  256. uint8_t wb;
  257. uint8_t pattern[] = { 0x00, 0xFF, 0x55, 0xAA };
  258. #if defined(__AVR_ENHANCED__) && !defined(__AVR_ATmega2561__)
  259. /*
  260. * Test external memory bus on ATmega128 systems.
  261. * Fails on the ATmega2561. Why?
  262. */
  263. if(XMemTestBus()) {
  264. return 0;
  265. }
  266. #endif
  267. /*
  268. * Enable external RAM.
  269. */
  270. #if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__)
  271. outb(XMCRA, _BV(SRE));
  272. #elif defined (__AVR__)
  273. outb(MCUCR, _BV(SRE));
  274. #endif
  275. /*
  276. * Let's see, how many kBytes we have. A simple pattern test on the
  277. * first bytes of each kilobyte boundary will do.
  278. */
  279. for (addr = first; addr >= first; addr += 1024) {
  280. mem = (uint8_t *)((addr + 1024) - sizeof(pattern));
  281. memcpy((void *)mem, pattern, sizeof(pattern));
  282. if(memcmp((void *)mem, pattern, sizeof(pattern))) {
  283. last = addr - 1;
  284. }
  285. /*
  286. * External RAM may not start at kilobyte boundary. Set the
  287. * address to full kilobytes after first test.
  288. */
  289. else if(addr == RAMEND + 1) {
  290. addr &= ~0x3FF;
  291. }
  292. }
  293. /*
  294. * Set all bits in RAM.
  295. */
  296. for (addr = first; addr >= first && addr < last; addr += 256) {
  297. memset((void *)addr, 0xFF, 256);
  298. }
  299. /*
  300. * Do an extensive test.
  301. */
  302. for (addr = first; addr >= first && addr < last; addr++) {
  303. mem = (uint8_t *)addr;
  304. /*
  305. * The next RAM location must still have all bits set. If not,
  306. * any manipulation on lower addresses may have modified this
  307. * one. Probably an address bus problem.
  308. */
  309. if(*mem != 0xFF) {
  310. merr_bits = ~*mem;
  311. merr_addr = (void *)mem;
  312. merr = MERR_BAD_ADDR;
  313. break;
  314. }
  315. /*
  316. * Do a walking bit test including all bits zero on the current
  317. * RAM location.
  318. */
  319. wb = 1;
  320. *mem = wb;
  321. do {
  322. if(*mem != wb) {
  323. break;
  324. }
  325. wb <<= 1;
  326. *mem = wb;
  327. } while(wb);
  328. /*
  329. * If the walking bit test hasn't finished or if not all bits
  330. * are cleared, then this data byte is broken.
  331. */
  332. if(wb || *mem) {
  333. if(wb) {
  334. merr_bits = *mem & ~wb;
  335. }
  336. else {
  337. merr_bits = *mem;
  338. }
  339. merr_addr = (void *)mem;
  340. merr = MERR_BAD_DATA;
  341. break;
  342. }
  343. }
  344. return last - first + 1;
  345. }
  346. /*!
  347. * \brief Test external banked SRAM.
  348. *
  349. * Banked memory is asumed on top of non-banked memory and the
  350. * start of banked memory is assumed on a 256 byte boundary.
  351. *
  352. * \return Number of banks available.
  353. */
  354. int XMemBankTest(size_t *xramsize)
  355. {
  356. volatile uint8_t *breg = (uint8_t *)((size_t)-1 & ~0xFF);
  357. volatile uint8_t *bmem = 0;
  358. size_t bsize = 16384;
  359. uint8_t *bend = (uint8_t *)bmem + bsize;
  360. uint8_t *xramend = (uint8_t *)(*xramsize + RAMEND + 1);
  361. volatile uint8_t *cp;
  362. uint8_t i;
  363. uint8_t j;
  364. /*
  365. * Determine the start address of banked memory. Switch to
  366. * bank 1 and set every 256th byte to 1. Then switch to bank 0
  367. * and clear every 256th byte. Next switch back to bank 1
  368. * and find the first location set to 1.
  369. */
  370. *(breg + 1) = 1;
  371. for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
  372. *cp = 1;
  373. }
  374. *breg = 0;
  375. for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
  376. *cp = 0;
  377. }
  378. *(breg + 1) = 1;
  379. for (cp = (uint8_t *)(RAMEND + 1); cp < xramend; cp += 256) {
  380. if(*cp == 1) {
  381. bmem = cp;
  382. break;
  383. }
  384. }
  385. /*
  386. * No RAM location kept the value of 1. There is no banked memory.
  387. */
  388. if(bmem == 0) {
  389. return 0;
  390. }
  391. *xramsize = xramend - bmem;
  392. for(i = 1; i; i++) {
  393. *(breg + i) = i;
  394. memset((void *)bmem, i, bsize);
  395. for(cp = bmem; cp < bend; cp++) {
  396. if(*cp != i) {
  397. break;
  398. }
  399. }
  400. if(cp < bend) {
  401. break;
  402. }
  403. /*
  404. * Test if non-banked memory is intact.
  405. */
  406. for (cp = (uint8_t *)(RAMEND + 1); cp < bmem; cp += 256) {
  407. if(*cp) {
  408. break;
  409. }
  410. }
  411. if(cp < bmem) {
  412. break;
  413. }
  414. for(j = 0; j < i; j++) {
  415. *(breg + j) = j;
  416. for(cp = bmem; cp < bend; cp++) {
  417. if(*cp != j) {
  418. break;
  419. }
  420. }
  421. if(cp < bend) {
  422. break;
  423. }
  424. }
  425. if(j < i) {
  426. break;
  427. }
  428. }
  429. return i;
  430. }
  431. /*
  432. * Read/write external SRAM until key pressed.
  433. */
  434. void LoopSRAM(void)
  435. {
  436. register unsigned int pattern;
  437. volatile uint8_t *mem;
  438. uintptr_t faddr = 0xFFFF;
  439. puts("Check address and data bus.");
  440. printf_P(presskey_P);
  441. for (;;) {
  442. for (pattern = 1; pattern; pattern <<= 1) {
  443. if (pattern <= RAMEND)
  444. mem = (uint8_t *) (pattern | (RAMEND + 1));
  445. else
  446. mem = (uint8_t *) pattern;
  447. *mem = (uint8_t) ((pattern >> 8) | pattern);
  448. }
  449. for (pattern = 1; pattern; pattern <<= 1) {
  450. if (pattern <= RAMEND)
  451. mem = (uint8_t *) (pattern | (RAMEND + 1));
  452. else
  453. mem = (uint8_t *) pattern;
  454. if (*mem != (uint8_t) ((pattern >> 8) | pattern))
  455. faddr = (uintptr_t) mem;
  456. }
  457. Delay(5000);
  458. if (GetChar()) {
  459. printf("No RAM at 0x%04X\n", (unsigned int)faddr);
  460. return;
  461. }
  462. }
  463. }