gbell@pnet12.cts.com (Greg Bell) (05/14/89)
I'm working on a microcontroller project using Intel's 8031. I have a 1x16 LCD, a DTMF decoder, and a line voltage detector as peripherals. I have a 2716 EPROM acting as a monitor ROM that loads a .OBJ file from my AT clone's COM port into the static RAM. Cuts software developement time 4x at least! Alright, enough of the description... I would like to battery back the RAM. Its a 6264LP-15. I have the appropriate diodes set up so the battery doesn't try to run the rest of the circuit, and so that it does not get charged by the power supply. How do I get the circuit to power down in an orderly fashion? As of now, the setup works many times, but occasionally the RAM gets corrupted. Its possible that the RAM is getting corrupted on each power-up/down but just becoming noticable when certain (instruction holding) locations get corr- upted. Is this RAM corruption due to a pulse on the WE/ (write enable) line? Or, is it because there's a program running in the RAM? Do I have to jump to some EPROM location before powering down just to assure the RAM isn't selected? I've tried having the setup jump to an EPROM address so the RAM is quiet at power down, and I still have the problem. Also, I've tried buffering the write line so that it can be pulled up when the power to the rest of the circuit goes down. Its hard to tell what's making a difference since I can't tell what, if any, locations get corrupted at any one time. I know Maxim and Dallas Semiconductor make chips that tame this problem, but I'm wondering if they're actually necessary. Does anyone have Dallas Semi's address? I'd like suggestions on how to track down the actual problem (finding out when the RAM is getting corrupted w/out printing out all RAM locations!) and whether a solution can be arrived at without using an entire IC. Greg Bell_________________________________________________________ Hardware hacker | Electronics hobbyist | UUCP: uunet!serene!pnet12!gbell EE major at UC San Diego |
henry@utzoo.uucp (Henry Spencer) (05/15/89)
My understanding is that it's non-trivial to build circuitry that will reliably keep a battery-backed RAM out of trouble during powerup and powerdown. If you want a solution quickly, buying one is probably simplest. >I know Maxim and Dallas Semiconductor make chips that tame this problem, >but I'm wondering if they're actually necessary. Does anyone have Dallas >Semi's address? Dallas Semi is at 4350 Beltwood Pkwy S, Dallas Texas 75244, (214)450-0400. They make a nice gadget called a "smart socket" that is probably just what you want -- it's a socket for a standard static RAM (actually there are several depending on exactly what size of RAM) that includes batteries and a switching circuit. Use one of these instead of a standard socket and you have battery backup. They are not inordinately expensive. -- Subversion, n: a superset | Henry Spencer at U of Toronto Zoology of a subset. --J.J. Horning | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
johne@hpvcfs1.HP.COM (John Eaton) (05/16/89)
<<<< < Alright, enough of the description... I would like to battery back the < RAM. Its a 6264LP-15. I have the appropriate diodes set up so the < battery doesn't try to run the rest of the circuit, and so that it does < not get charged by the power supply. ---------- Thats the first step. You must also ensure that the CS2 is driven DEEPLY into its inactive state during power down. By deeply I mean to within 200 mv of the rails because the static current at Vih or Vil is about 500X the current when driven to the rails. It is extremely important that you guarentee that the ram is not accessed during powerdown because even a read will cause its current to jump by a factor of about 30,000. When doing a battery backed design you must ensure that no signal from the battery section is allowed to drive ANY unpowered device pin high. If you do then the signal will attempt to power its VDD line through the input protection diodes and you will see high current. If its a CMOS design then the circuit may even still run. Power down the circuit and check the voltage at the VDD pins of the chips that should be off. If you see 1 to 2 volts then you have problems. John Eaton !hpvcfs1!johne
cook@stout.ucar.edu (Forrest Cook) (05/16/89)
In article <657@serene.UUCP> gbell@pnet12.cts.com (Greg Bell) writes: >Alright, enough of the description... I would like to battery back the >RAM. Its a 6264LP-15. Call your MOSTEK sales rep and ask for their "zeropower rams". They come in standard 2K X 8 and 8K X 8 packages with built in long life lithium cells. I have used a version that is a 2K X 8 chip with the last 8 bytes dedicated to a built in real-time clock. It has worked flawlessly for several years and the battery is only drained when the power is off. They offer a special low power mode for storage. I think one of the part numbers is MK48T02, I may be wrong on that one. ^ ^ Forrest Cook - Beware of programmers who carry screwdrivers - LB /|\ /|\ cook@stout.ucar.edu (The preceeding was all my OPINION) /|\ /|\ {husc6|rutgers|ames|gatech}!ncar!stout!cook /|\ /|\ {uunet|ucbvax|allegra|cbosgd}!nbires!ncar!stout!cook
davidc@vlsisj.VLSI.COM (David Chapman) (05/16/89)
In article <657@serene.UUCP> gbell@pnet12.cts.com (Greg Bell) writes: >How do I get the circuit to power down in an orderly fashion? ... > >Is this RAM corruption due to a pulse on the WE/ (write enable) line? ... > >I've tried having the setup jump to an EPROM address so the RAM is quiet >at power down, and I still have the problem. Also, I've tried buffering >the write line so that it can be pulled up when the power to the rest of >the circuit goes down. Its hard to tell what's making a difference since >I can't tell what, if any, locations get corrupted at any one time. > You really don't want to have anything running during the power-down period. If you can feed the "power down pending" signal to the non- maskable interrupt line of the processor, and have it HALT, that might reduce the incidence of the problem. If you don't have advance notice of power failure, then you need a power-fail-detection circuit and you might as well buy the special chips. You say that you pulled up the WE line during power-down. Was the IC that pulled this up also powered from the RAM battery? If not, it might get pulsed as power fails to the IC that pulls it up. Very strange things happen to digital ICs as the voltage drops towards 0. This might be random enough to explain your problems as well. Think of what happens to the processor as it loses power. Do you want it to be running a program? Nooo. In fact, all of the circuitry that isolates the RAM must be powered by the battery. If it's CMOS this won't be a power consumption problem. Just make sure it runs at the voltage supplied by the battery (3V, I presume). As Henry Spencer said, it might be easier just to buy one of the chips designed for this purpose, but you should be able to do it yourself. That's the hardware hacking spirit. If you're really concerned about detecting RAM corruption problems during power cycling, put a CRC routine into the power-down code. This can be done in a few (~50) lines of assembly language on most processors. I have public-domain C source code and (never-tested) 80x86 assembly language that I can e-mail or post if you want. BTW, the same code checks on power-up. David Chapman {known world}!decwrl!vlsisj!fndry!davidc vlsisj!fndry!davidc@decwrl.dec.com
jpexg@hermes.ai.mit.edu (John Purbrick) (05/16/89)
Recently I've seen huge (electrically, not physically) capacitors in the Digi-Key catalog. A whole farad! They have fairly high internal resistance (~50 ohm) but to keep a trickle going into a memory chip, which is what they're designed for, they should be OK. Whether something like this would do the job depends on how long the system has to be kept alive without being plugged in, which would recharge the cap of course.
gbell@pnet12.cts.com (Greg Bell) (05/16/89)
johne@hpvcfs1.HP.COM (John Eaton) writes: ><<<< >< Alright, enough of the description... I would like to battery back the >< RAM. Its a 6264LP-15. I have the appropriate diodes set up so the >< battery doesn't try to run the rest of the circuit, and so that it does >< not get charged by the power supply. >---------- >Thats the first step. You must also ensure that the CS2 is driven >DEEPLY into its inactive state during power down. By deeply I mean to >within 200 mv of the rails because the static current at Vih or Vil is >about 500X the current when driven to the rails. It is extremely important >that you guarentee that the ram is not accessed during powerdown because >even a read will cause its current to jump by a factor of about 30,000. > Really? A read will cause problems? In other words, I need to jump to a location in the monitor EPROM before powering down (there's no way to get the 8031 to just "HALT". Maybe driving RESET high and holding it would do)? Would the Maxim/Dallas Semi monitor chips pull the CS2 inactive soon enough so that the circuit could be doing anything at powerdown without trouble? After all, isn't that the purpose of the chip? Greg Bell_________________________________________________________ Hardware hacker | Electronics hobbyist | UUCP: uunet!serene!pnet12!gbell EE major at UC San Diego |
davidc@vlsisj.VLSI.COM (David Chapman) (05/18/89)
In article <662@serene.UUCP> gbell@pnet12.cts.com (Greg Bell) writes: >johne@hpvcfs1.HP.COM (John Eaton) writes: >> ... It is extremely important >>that you guarentee that the ram is not accessed during powerdown because >>even a read will cause its current to jump by a factor of about 30,000. > >Really? A read will cause problems? In other words, I need to jump to a >location in the monitor EPROM before powering down (there's no way to get the >8031 to just "HALT". Maybe driving RESET high and holding it would do)? The reason that power consumption rises is (as someone else already mentioned) that you end up trying to power the rest of the circuit through the SRAM's data lines. This can do nasty things to your battery, like maybe make its output voltage drop momentarily. It could also damage the SRAM. Remember, these circuits are not designed to work at 1-2 volts, even for a few milliseconds as the circuit powers down. You don't know what they will do. Normally, you don't care because any state change is going to get lost when power drops to 0. Now you do care. So in order to keep from frying or scrambling your SRAM, you must logically (if not electrically) isolate it from the rest of the circuit as soon as the power supply voltage starts to drop. If you can keep the chip from being selected, that will prevent problems even if the read line is being pulsed. I hadn't thought of the CS2 line before (I _knew_ there were other control lines besides the WR :-), but now I remember that some circuits (and chips) use an active-high CS line as a battery backup isolater. They put a 4.5V sensor on it, and you tie it to Vdd (_not_ the battery). As power drops the SRAM cuts out. This may be the salient feature of the SRAMs recommended elsewhere, and might be included in the SRAM with its own battery on-board. Wrt the latter, I'd be worried if my system were to have a significant lifetime (>3 years). How do you know that the internal battery is dying _before_ you lose data the next time you power down? David Chapman {known world}!decwrl!vlsisj!fndry!davidc vlsisj!fndry!davidc@decwrl.dec.com
nagle@well.UUCP (John Nagle) (05/18/89)
I've used a New Micros M68HC11 microprocessor board with a "smart socket" keeping the static RAM alive. An interesting implication of this is the behavior of the system when power is low. I was powering the board with a battery and a 7805 regulator. When the battery voltage dropped below about 6v, the output of the regulator fell from the regulated 5v level. This didn't bother the microprocessor, an all-CMOS device that will run quite happily on 3v. But the "smart socket" detected the loss of power and took the RAM offline. This caused the processor to crash and restart. This M68HC11 had a Forth interpreter mask-programmed onto the chip, and the Forth interpreter, at startup, searched RAM for a special pattern indicating the start of the program to be run. Not finding it, it simply offered a Forth prompt to the terminal. So, unexpectedly, the embedded application stopped running and the Forth interpreter's prompt appeared, with a working Forth system available using only the 1K of RAM on the M68HC11 chip, and the 32Kb on the "protected" chip offline. This puzzled us for a while. John Nagle
gbell@pnet12.cts.com (Greg Bell) (05/20/89)
Wow. I've been overwhelmed with replies, suggestions, tips, etc. Many thanks to everybody that took the time to E-mail me. I'm pretty much convinced that the main problem is that although I solved the problem of leaving the WE line floating by using a pull up resistor, the uP is tugging the WE low as it dies. Many people recommended I purchase one of the RAM-in-a-socket contraptions. I'd prefer not to do it this way since this project is a hacking experience for me. I think I'm going to go with one of the power monitor chips that will disable the RAM's CS as soon as it sees the main power start to fall. Yet another question, aimed at David C: if the power monitor chip pro- tects the RAM by putting in in low power mode (disabling one of the CS lines), will this solve the problem of the rest of the circuit getting power through the data lines? I assume this can only happen through output lines and not input lines. If the CS is just yanked inactive, then it really shouldn't matter what the processor is doing. The processor can do any number of things as the power drops anyway. Things on the processor end are basically unpredictable, so the RAM has to be protected directly. Seems that the NMI, RESET, and HALT related solutions wouldn't work. Thanks again, everybody... lets keep this conversation going! Interesting stuff. (By the way, DavidC, could you send the CRC code you mentioned? ) (and, to the guy who E-Mailed me from Arizona or New Mex about ) (robotics... I lost your address and my reply bounced. Try again) Greg Bell_________________________________________________________ Hardware hacker | Electronics hobbyist | UUCP: uunet!serene!pnet12!gbell EE major at UC San Diego |
davidc@vlsisj.VLSI.COM (David Chapman) (05/24/89)
In article <669@serene.UUCP> gbell@pnet12.cts.com (Greg Bell) writes: >Yet another question, aimed at David C: if the power monitor chip pro- >tects the RAM by putting in in low power mode (disabling one of the CS lines), >will this solve the problem of the rest of the circuit getting power through >the data lines? I assume this can only happen through output lines and not >input lines. Yes, the problem is driving through the output lines. Disabling the RAM should keep you out of trouble. >(By the way, DavidC, could you send the CRC code you mentioned? ) Coming up... (sorry it took so long to respond; we had a major network upgrade last week). It's all in the next post (those of you who don't care are hereby warned). David Chapman {known world}!decwrl!vlsisj!fndry!davidc vlsisj!fndry!davidc@decwrl.dec.com
davidc@vlsisj.VLSI.COM (David Chapman) (05/24/89)
I've had a couple of requests for the CRC code that I mentioned. So at the risk of offending the net gods by wasting all of their precious bandwidth, here it is (yes, I realize that it should be in comp.sources.whatever, but I don't read them and I suspect few of you do). If you're not interested in CRCs, type 'n' now. There are four files encapsulated herein: pdcrc.c, crc.h, crc.c, and crc.asm. Each is separated by a form feed and prefixed with a line of the form "#file <file name>". "pdcrc.c" is (I believe) a public domain set of CRC routines. It came from an MS-DOS disk of C source code; wish I could remember where. It's documented to the extreme. Possible porting problem: the author assumes that "short" is 16 bits; I've seen 8-bit shorts on some machines. It also assumes that adding a character to a long will be unsigned; some machines perform signed character arithmetic. Files crc.h and crc.c are the interface and implementation, respectively, of my version of the same code. I changed the implementation from long integer registers to regular integers for speed (especially important on 16-bit processors that barely slog through 32-bit operations). It's been a year since I worked on it, but I recall having tested it with the main() from pdcrc.c. I recommend that you test it thoroughly yourself, of course. Possible porting probems: it assumes that integers are 16 bits (though it should work regardless). Itassumes that casting a character to an unsigned int works (had a bug in a compler once that wouldn't allow that!). File crc.asm is the _untested_ translation of crc.c to MASM for 80x86 processors. As you'll see pretty quickly, it won't even assemble yet (segment info is missing, etc.). I think that the inner loop will work properly if you get the procedure shell around it, load the values properly, etc. Note that the reference to "[00]" is a data segment load (I think - I'm not an expert 80x86 programmer yet). This was an exercise to see how easy and fast a CRC could be in assembly language, given a carry bit. It's fewer lines, and generates an order of magnitude less code! I bet it's at least one order of magnitude faster, too. Files crc.c and crc.h are hereby released into the public domain for use as you see fit. Since I can't prove that pdcrc.c is in the public domain (without more effort than my classes allow me right now), you may wish to use those instead. Crc.asm is similarly released, but by the time you get it working it won't be recognizable as my code anyway, so you're outof danger. Remember: you get what you paid for (don't sue me). David Chapman {known world}!decwrl!vlsisj!fndry!davidc vlsisj!fndry!davidc@decwrl.dec.com #file pdcrc.c /****************************************** * * * Cyclic Redundancy Check (CRC) functions * * * ******************************************/ /* * crc_clear: * This function clears the CRC to zero. It should be called prior to * the start of the processing of a block for both received messages, * and messages to be transmitted. * * Calling sequence: * * short crc; * crc = crc_clear(); */ short crc_clear() { return(0); } /* * crc_update: * this function must be called once for each character which is * to be included in the CRC for messages to be transmitted. * This function is called once for each character which is included * in the CRC of a received message, AND once for each of the two CRC * characters at the end of the received message. If the resulting * CRC is zero, then the message has been correctly received. * * Calling sequence: * * crc = crc_update(crc,next_char); */ short crc_update(crc,crc_char) short crc; char crc_char; { long x; short i; /* "x" will contain the character to be processed in bits 0-7 and the CRC */ /* in bits 8-23. Bit 24 will be used to test for overflow, and then cleared */ /* to prevent the sign bit of "x" from being set to 1. Bits 25-31 are not */ /* used. ("x" is treated as though it is a 32 bit register). */ x = ((long)crc << 8) + crc_char; /* Get the CRC and the character */ /* Repeat the following loop 8 times (for the 8 bits of the character). */ for(i = 0;i < 8;i++) { /* Shift the high-order bit of the character into the low-order bit of the */ /* CRC, and shift the high-order bit of the CRC into bit 24. */ x = x << 1; /* Shift "x" left one bit */ /* Test to see if the old high-order bit of the CRC was a 1. */ if(x & 0x01000000) /* Test bit 24 of "x" */ /* If the old high-order bit of the CRC was a 1, exclusive-or it with a one */ /* to set it to 0, and exclusive-or the CRC with hex 1021 to produce the */ /* CCITT-recommended CRC generator of: X**16 + X**12 + X**5 + 1. To produce */ /* the CRC generator of: X**16 + X**15 + X**2 + 1, change the constant from */ /* 0x01102100 to 0x01800500. This will exclusive-or the CRC with hex 8005 */ /* and produce the same CRC that IBM uses for their synchronous transmission */ /* protocols. */ x = x ^ 0x01102100; /* Exclusive-or "x" with a...*/ /* ...constant of hex 01102100 */ /* And repeat 8 times. */ } /* End of "for" loop */ /* Return the CRC as the 16 low-order bits of this function's value. */ return(((x & 0x00ffff00) >> 8)); /* AND off the unneeded bits and... */ /* ...shift the result 8 bits to the right */ } /* * crc_finish: * This function must be called once after all the characters in a block * have been processed for a message which is to be TRANSMITTED. It * returns the calculated CRC bytes, which should be transmitted as the * two characters following the block. The first of these 2 bytes * must be taken from the high-order byte of the CRC, and the second * must be taken from the low-order byte of the CRC. This routine is NOT * called for a message which has been RECEIVED. * * Calling sequence: * * crc = crc_finish(crc); */ short crc_finish(crc) short crc; { /* Call crc_update twice, passing it a character of hex 00 each time, to */ /* flush out the last 16 bits from the CRC calculation, and return the */ /* result as the value of this function. */ return(crc_update(crc_update(crc,'\0'),'\0')); } /* * This is a sample of the use of the CRC functions, which calculates the * CRC for a 1-character message block, and then passes the resulting CRC back * into the CRC functions to see if the "received" 1-character message and CRC * are correct. */ main() { short crc; /* The calculated CRC */ char crc_char; /* The 1-character message */ char x, y; /* 2 places to hold the 2 "received" CRC bytes */ crc_char = 'A'; /* Define the 1-character message */ crc = crc_clear(); /* Reset the CRC to "transmit" a new message */ crc = crc_update(crc,crc_char); /* Update the CRC for the first... */ /* ...(and only) character of the message */ crc = crc_finish(crc); /* Finish the transmission calculation */ x = (char)((crc & 0xff00) >> 8); /* Extract the high-order CRC byte */ y = (char)(crc & 0x00ff); /* And extract the low-order byte */ printf("%04x\n",crc); /* Print the results */ crc = crc_clear(); /* Prepare to "receive" a message */ crc = crc_update(crc,crc_char); /* Update the CRC for the first... */ /* ...(and only) character of the message */ crc = crc_update(crc,x); /* Pass both bytes of the "received"... */ crc = crc_update(crc,y); /* ...CRC through crc_update, too */ printf("%04x\n",crc); /* If the result was 0, then the message... */ /* ...was received without error */ } #file crc.h /* crc.h - interface for 16-bit CRC routines */ /* I assume two-byte integers. */ typedef unsigned int CRCSHORT; /* return value type */ #ifndef UNIX /* no function prototyping in UNIX C */ CRCSHORT crcupdate(char,CRCSHORT); /* update the CRC with the given */ /* 8-bit value. */ CRCSHORT crcval(CRCSHORT); /* return the final CRC, given */ /* working value so far */ CRCSHORT crcstr(char *); /* compute CRC value of string */ CRCSHORT crcstrn(char *,int); /* compute CRC value of "len" chars */ #else UNIX CRCSHORT crcupdate(),crcval(),crcstr(),crcstrn(); #endif /* usage: char *p; CRCSHORT crc; crc = 0; while (*p) crc = crcupdate(*p++,crc); crc = crcval(crc); append "crc" to the string and transmit the entire thing. at the receiving end, pass each character (including the trailing CRC bytes) through the crcupdate() function again, and 0x0000 should result. if not, something got corrupted. this particular code example is how "crcstr" is implemented. */ #file crc.c /* crc.c - 16-bit cyclic redundancy check */ /* uses the CCITT-recommended function X**16 + X**12 + X**5 + 1. */ /* in the polynomial definition below, the uppermost bit is assumed. this */ /* allows the use of shorter numbers than otherwise would be required. */ #define CRC16POLY 0x1021 /* CCITT-16 polynomial in hex */ #include "crc.h" CRCSHORT crcupdate(ch,crc) /* update the CRC with the given */ char ch; /* 8-bit value. */ CRCSHORT crc; { /* for speed all of this should really be done in assembly language */ /* judicious use of the carry flag would make the temporary flags */ /* superfluous). */ int i; register unsigned c,bit,exor; c = (unsigned) ch; for (i = 0; i < 8; ++i) { bit = (c > 0x7f); /* 1 or 0 from high bit */ c = (c << 1) & 0xff; exor = (crc & 0x8000); /* just non-zero is OK here */ crc = (crc << 1) | bit; if (exor) /* recirculation... */ crc ^= CRC16POLY; } /* end of for (i) */ return(crc); } /* end of crcupdate() */ CRCSHORT crcval(crc) /* return the current CRC, given */ CRCSHORT crc; /* working value so far */ { /* we pass 0x0000 through, and the caller appends the resulting CRC */ /* to its byte stream. at the other end the final CRC of the stream */ /* (including the CRC passed in) should be 0x0000. */ crc = crcupdate('\0',crc); return(crcupdate('\0',crc)); } /* end of crcval() */ CRCSHORT crcstr(str) /* compute CRC of '\0' terminated */ char *str; /* string (not including '\0') */ { CRCSHORT crc; crc = 0; while (*str) crc = crcupdate(*str++,crc); return(crcval(crc)); } /* end of crcstr() */ CRCSHORT crcstrn(str,len) /* compute CRC of "len" chars of str */ char *str; int len; { int i; CRCSHORT crc; crc = 0; for (i = 0; i < len; ++i) crc = crcupdate(*str++,crc); return(crcval(crc)); } /* end of crcstrn() */ #file crc.asm ; ; CRCUPDATE - run a character through the CRC generator ; ; hand optimized for the 8086, with C code for you machine- ; independent types (several times slower! optimizing compilers ; usually can't tell that the binary flags "bit" and "exor" are ; really carry flag hacks...). ; ; #define CRC16POLY 0x1021 ; ; void crcupdate(ch) ; char ch; ; { ; int i; ; register unsigned c,bit,exor; ; ; for (i = 8; i; --i) { ; bit = (c > 0x7f); ; c = (c << 1) & 0xff; ; exor = (_crc16 & 0x8000); ; _crc16 = (_crc16 << 1) | bit; ; if (exor) ; _crc16 ^= CRC16POLY; ; } /* end of for (i) */ ; ; } /* end of crcupdate() */ ' crcupdate: mov ax,[00] ;get _crc16 mov bl,6[bp] ;c = (unsigned) ch; mov cx,8 ;for (i = 8; i; --i) shiftloop: ;{ shl bl,1 ; bit = (c < 0x7f); ; c = (c << 1) & 0xff; rcl ax,1 ; exor = (_crc16 & 0x8000); ; _crc16 = (_crc16 << 1) | bit; jnc noexor ; if (exor) xor ax,1021H ; _crc16 ^= CRC16POLY; noexor: loop shiftloop ;} mov [00],ax ;save _crc16 ;assorted stack manipulation... ret