12v to 3.3v converter for GPIO. - Page 1
Forum section: electronics / general

author: luiHS
author_rank: Frequent Contributor
timestamp: April 30, 2023, 01:43:47 am
content: HiI have a project that needs to read 12v signals through the GPIO ports of a microcontroller. It is an 8x8 switch matrix, the machine's electronics scan the columns of these matrix and give the status of the 8 row switches. I cannot change the electronics of that machine at 12v, I have not done it, the circuit that I have designed has to be connected to that machine and read those signals.At first I used a 4050, but I have had problems because of the propagation time that is very slow, there are even differences between CD4050, HEF4050 and MC14050. Now I can only use the MC14050 because the delay times that I have set by software to read the data only work with the MC14050, if I put another variant of the 4050 it no longer works well.So it occurred to me to replace the 4050 with inverted diodes, the BAS16VY. At the output of the diodes, a 3.3v pullup resistor and an array of 2.2nF capacitors to ground. This seems to work for now.But I'd like to use something on a single chip, like a 4050 or 74LVC, but that will take 12v input signals with a 3.3v output and have a fast propagation time.Any suggestions?Thx.

author: dobsonr741
author_rank: Frequent Contributor
timestamp: April 30, 2023, 02:02:28 am
content: Can you please provide a schematics? Of what the original machine was, and what the attempt was with the 4050 that did not work.

author: james_s
author_rank: Super Contributor
timestamp: April 30, 2023, 02:12:55 am
content: You should be able to get away with using resistor dividers if it's only inputs. You could use resistor networks to simplify the construction.

author: brucehoult
author_rank: Super Contributor
timestamp: April 30, 2023, 02:23:21 am
content: Do you really need to have this current amplification function? Those chips have about 1 µA inputs and 5 mA outputs. I guess that's the main source of the 50-100 ns propagation delay (which doesn't seem to be all that long tbh).The chances are your switch electronics can supply a lot more than 1 µA, and also your microcontroller probably doesn't need more than 1 µA to its GPIO pins.Why can't a simple resistor voltage divider do the job? Say a 10k between gnd and your GPIO input, and a 27k or 33k between the GPIO and the 12V data input?

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 30, 2023, 04:42:53 am
content: Quote from: luiHS on April 30, 2023, 01:43:47 amhowexactly doesthe machine's electronics scan the columns of these matrix and give the status of the 8 row switches.Do you have their internal circuit ?Quote from: luiHS on April 30, 2023, 01:43:47 amThat makes little sense, relative to a switch matrix, any 4050 should be plenty fast enough << 1us.You may be missing another factor here ?Another parallel part you could try, is a ULN2803 or variant, that has a pull down resistor, which may be what is missing here ?

author: westfw
author_rank: Super Contributor
timestamp: April 30, 2023, 04:56:36 am
content: QuoteThat seems very unlikely. Even old CMOS logic ought to be "very fast" compared to the sort of human-oriented timings of a switch matrix. I implemented a whole keyboard from the basic design in Lancaster's CMOS Cookbook, and that was at 5V, which ought to be slower than it can run at 12V. (and it might have used A-series chips!)(Datasheet says propagation time with Vin=10V, Vcc=5V is significantly less than 100ns. I hope your keyboard isn't scanning anywhere near 10MHz!)

author: Faranight
author_rank: Unknown
timestamp: April 30, 2023, 06:38:47 am
content: Hypothetically speaking, how much overvoltage protection does a setup with a resistor divider network offer in this case (12V to 3.3V with resistors in some 10 kOhm range)?If the user can expect some overvoltage to appear on the 12V input, can the internal uC pin protection diodes handle the current or is there external protection circuitry needed?

author: RoGeorge
author_rank: Super Contributor
timestamp: April 30, 2023, 07:18:32 am
content: If you need to output 12V pulses to scan the keys, there are open collector TTL chips that have normal TTL inputs (TTL still works with 3.3V inputs) and can support up to 15-30V output pullup (e.g. SN7407https://www.ti.com/lit/ds/symlink/sn7407.pdf). For inputs, a resistor divider.If the lines has to be bidirectional, there are level shifters chips, with a transistors for each direction, either bipolar or MOSFET, like this (don't know by heart the part number that can level shift from 3V3 to 12V), like this:https://electronics.stackexchange.com/questions/296879/logic-level-converter-using-transistors

author: luiHS
author_rank: Frequent Contributor
timestamp: April 30, 2023, 01:21:48 pm
content: Well, in this design I really run into two problems.1.- I connect the columns of the matrix to the GPIO of a microcontroller, in principle I used the 4050, and by software I configure interrupts for each port connected to a column. Regardless of using the 4050, I noticed that the interruptions were triggered incorrectly, so I checked with the oscilloscope that there are fluctuations in the 12v, the machine does not use a stabilized voltage. In case the machine had a fault, I checked and changed the diode bridges, filter capacitors, even the power transformer, but the 12v fluctuation was not resolved. So I changed the design to the one I attached, diode, pullup resistor to 3.3v and 2.2nF capacitor to ground, this works.2.- For the reading of the rows, I have left the 4050, but by program I have to put a small delay to read the rows, when the column interrupt is triggered, if I don't then the data is still not available. This I suppose is the propagation time of the 4050, which is very high compared to others like the 74LVC, I checked it in the datasheet and the differences in the propagation times are great. Also, some time ago I had that kind of problem with another circuit that didn't work well for me with the 4050, I replaced it with a 74LVC245 and it worked perfectly.To make matters worse, there are also differences in the propagation time between different manufacturers of the 4050, so with the MC14050 and the delay that I put in software, the row signals are read fine, but if I put a HEF4050 or CD4050 they already fail , I guess for trial and error I would have to calculate a new software delay to capture the state of all 8 rows when the column interrupt is triggered.The circuitry of the machine, which I cannot change, I only capture these signals and process them with my circuit using a Kinetis MK66 microcontroller and in a new version an RT1064, it consists of a processor that scans the 8 columns with a ULN2803, so that the active column is at 0v and the rest at 12v with pullup resistors. To read the rows it uses LM339 operational configured as comparators to convert the 12v to 5v and from there with 74xx chips it reads them with the microprocessor. I didn't want to use that circuitry with the LM339 to simplify it, I thought that with a 4050 it could work (only for the rows), and although it does it by delaying the data capture with a software delay, I would prefer a cleaner hardware solution.I think that both rows and columns could work with the attached diagram, I use the diodes in arrays of 3 with the BAS16VY, the resistors in arrays of 8 and the capacitors in arrays of 4.The question is if there is a chip that allows to convert logic levels from 12v to 3.3v, and that is fast enough, like a 74LVC245, but it only admits maximum 5v signals.Use a resistive divider to read the rows, I don't know if it will work due to the fluctuations in the 12v logic level, I would have to try it.

author: brucehoult
author_rank: Super Contributor
timestamp: April 30, 2023, 01:32:07 pm
content: Quote from: luiHS on April 30, 2023, 01:21:48 pm180 MHz and 600 MHz "microcontrollers" to read a keyboard? Level shifters with 50 ns or 100 ns propagation delay are too slow?It is normal with keys and switches to use a debounce time of 20 ms (20,000,000 ns) or so. Certainly more than 1 ms.What on earth is going on here?

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 30, 2023, 02:54:07 pm
content: The issue is not propagation delay, but capacitive load, you must wait enough time for the 2.2nf capacitor to charge up, also discharge it before scanning the next row.It's more than likely you can do the entire thing with just resistor dividers (10K from input to pin, then 3k3 from pin to gnd) and proper software debouncing, using the usual 1KHz systick ISR for the scanning routines will be more than fast enough, you only have to scan 8 sequential rows, while reading 8 columns at once, noting down the last value, last stable values (when having same state for >20ms), exposing the stable values to the software.Regardless of switching noises, the value should be stable when a key is released or pressed.For example:Code:typedef struct {uint8_t stable; // stable values of 8x8 arrayuint8_t last; // last values of 8x8 arrayuint8_t row; // current row being scanneduint8_t row_time; // row delay timeruint32_t last_time; // last time each key changed}keypad_t;volatile keypad_t keypad;void update_column(void){keypad.last[keypad.row] = GPIOA->IDR & 0xFF; // I.e. Port A 8 LSB.}void update_row_gpio(void){switch (keypad.row){case 0: // pseudo coderow_7_pin=0;row_0_pin=1;break;case 1:row_0_pin=0;row_1_pin=1;break;(...)case 7:row_6_pin=0;row_7_pin=1;break;}}void keypad_isr(void){ // called from systick @ 1khzif(keypad.row_timer++ < 1){return; // Let each row charge for 1ms}keypad.row_timer=0; // reset row timeruint32_t now = getTick(); // get current tick valueupdate_column(); // Some routine that reads the 8 column bits into keypad.last[keypad.row];uint8_t change = keypad.last[keypad.row] ^ keypad.stable[keypad.row]; // XORfor(uint8_t col=0; col<8; col++){ // update stable valuesif (change & 1<<col) {keypad.last_time[keypad.row] = now; // reset timer on change}else if(now - keypad.last_time[keypad.row] >=20) { // 20ms with same valuekeypad.stable[keypad.row] = (keypad.stable[keypad.row] & ~bit) | (keypad.last[keypad.row] & bit); // Clear stable bit, update with last value}}if(++keypad.row > 7){ // Update scanning rowkeypad.row = 0;}update_row_gpio(); // Some routine that sets the correct GPIO for the current keypad row.}void get_key(uint8_t key){ // Read debounced key status, from 0 to 63, called from normal programreturn (keypad.stable[key/8] & 1<<(key%8);}

author: Nominal Animal
author_rank: Super Contributor
timestamp: April 30, 2023, 07:00:29 pm
content: Quote from: brucehoult on April 30, 2023, 01:32:07 pmIt's the "MCU is so fast I want the peripherals to match, because otherwise the software gets more complicated to write" problem.Absolutely no offense/snarkiness/snideness meant, luiHS; I mean the above in the literal sense. The "better-but-more-complicated" software approach (including software debounce) is to set up the next row immediately after reading, but then do something else useful for the duration. Using a 1 kHz interrupt (1000 rows per second, thus each key 125 times each second) gives you a maximum key state change latency of 8 ms; 8 kHz interrupt a max latency of 1 ms. Because I like to minimize the latency, my software debouncing uses the "inactivity period counter" approach: a per-key counter is initialized to a suitable number, and decremented until zero each interrupt; with a nonzero counter meaning the state is not checked.My preferred implementation uses two bytes per key, in separate arrays. One array is for the inactivity counters, that also act as the autorepeat interval counters. The other array acts as key pressed event flags, with the interrupt only setting the flag, and main loop code clearing the flag when performing the key press event. If you use a full byte per key (and check the compiler usesLDRB/LDRSBfor reading it andSTRBfor clearing it, for both MK66 and RT106x), you won't need any locking at all. This works even when a single keypress "peck" is faster than a main loop iteration. To incorporate the initial-repeat and auto-repeat intervals to the same counter, you can use an extra bit (either LSB, or separate actions depending on positive/negative counter value) to distinguish between debounce and repeat.Thisismore complex than when the matrix row switching is approximately as fast as the MCU, so that you can just read the entire matrix in a single loop without significant time lost between rows (and no need to spend that time doing something else useful). My approach is more efficient, because each interrupt only reads a single row (8 keys) and updates their states, so the only time "lost" is interrupt overhead; but the code is more complex, and one needs to think of things like main loop code modifying button state just as an interrupt fires and updates those states also –– and also what kind of latency issues such an interrupt firing at a random moment for other code causes.

author: Nominal Animal
author_rank: Super Contributor
timestamp: April 30, 2023, 08:40:31 pm
content: Quote from: SiliconWizard on April 30, 2023, 07:59:34 pmIf something gets you to roll your eyes, the least thing you can do is explain why, instead of just showing your condescension like a dick.Not everyone of us perceives all the things that are obvious to you.

author: Zero999
author_rank: Super Contributor
timestamp: April 30, 2023, 09:12:06 pm
content: Quote from: RoGeorge on April 30, 2023, 07:18:32 amA J-FET will also work. It just needs to have a cut-off voltage of >-3.3V. J113 or PN4391 should work for J1, instead of 2N4393.Yes I know this is probably unnecessary. A plain old potential divider will probably do.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 30, 2023, 09:44:25 pm
content: Quote from: luiHS on April 30, 2023, 01:21:48 pmThat's old-school, but perfectly valid and multi-sourced.If you have a working scan design, why change it ? Are you making thousands of these ?In 2023 you could look at LED drivers with read-back/diagnostics, for a reduced wires solution, but multi sourcing is trickier.Or go with a generic IO expander like xxA9555 and code scanning software, or use a low cost MCU as a key pad reader.Ironically, TSSOP20 MCUs can cost less than generic IO expanders ?!

author: David Hess
author_rank: Super Contributor
timestamp: May 01, 2023, 12:02:02 am
content: A pair of 1489 quad line receivers intended for RS-232 level translation might be suitable.

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 01, 2023, 03:34:39 am
content: Quote from: Nominal Animal on April 30, 2023, 08:40:31 pmEasy there. It was just a smiley. And I'm a condescending dick.Should have quoted or added possibly some context, but the whole idea of a 4050 not being fast enough for scanning a keyboard, and requiring a Cortex-M7 running at hundreds of MHz to handle a keyboard was a tad much. And Bruce's "What on earth is going on here?" sounded about right. Since we didn't get any further reply from the OP, the question remains unanswered and the rest is just speculation.So, I'll remove the smiley if you feel offended by it, and I'll replace it with a second "what on earth is going on here?".

author: Nominal Animal
author_rank: Super Contributor
timestamp: May 01, 2023, 04:45:21 am
content: Quote from: SiliconWizard on May 01, 2023, 03:34:39 amSure, I can agree with that.Quote from: SiliconWizard on May 01, 2023, 03:34:39 amWell, to me, their post#8, especially"by software I configure interrupts for each [column input]"and "I have to put a small delay to read the rows, when the column interrupt is triggered"indicated that the true problem is that the software solution chosen is simplistic, and my reply#11(to brucehoult) names the problem and outlines the standard software-debounced, interrupt-per-row scanning routine, with a pointer towards autorepeat and how to avoid missing keypresses and how to avoid sync issues wrt. interrupt updates and main loop updates without resorting to any kind of locks. (Anyway, I was wrong, too; the problem luiHS has is different.)I'm pretty sure you'll agree that if our places were reversed (and they have been in the past, in other threads), you'd be miffed at me if I had just posted an eyeroll, too.Quote from: SiliconWizard on May 01, 2023, 03:34:39 amNo, no, it is not about offense. It is about posting only a reaction/opinion, and not the focus/reason for it, leaving us hanging and wondering what it is that you reacted to. It wasn't obvious to me.Plus, because of this exchange, I realized my own advice to luiHS was useless.

author: Nominal Animal
author_rank: Super Contributor
timestamp: May 01, 2023, 06:28:00 am
content: Dammit. luiHS, your setup differs from typical ones in such unusual ways, my advice earlier is useless to you. Apologies.Let me swap rows and columns; it's just much easier for me that way.Quote from: luiHS on April 30, 2023, 01:43:47 amYou have 8 row selector inputs, and 8 column data inputs.The external keyboard matrix, not the microcontroller, is in control of the row selection. The active row is pulled low, while the rest of the row selector inputs stay high. I shall assume you also have the 12V available (if nothing else, then via 1-7 common-cathode diodes from the row selectors).The problem is that using the row selector inputs as the interrupt trigger for the microcontroller occurs before the column data inputs have stabilized (due to whatever delays or capacitances involved in the circuit).The software solution would be to have the row selector inputs with falling edge interrupts, with the same interrupt handler, that arms a pre-prepared timer (of about 1µs), whose interrupt handler causes the column data to be read and processed.Another alternative is to use a high frequency timer interrupt, that reads the row selector inputs, and only reads and processes the column data inputs when only one of the row selector inputs has been low for three times in row. The interrupt frequency should be 4x to 8x the maximum frequency at which the row selector inputs may change (so that this interrupt occurs at least 4 to 8 times per active row).I think a hardware solution, something based on an 8-way AND or NAND gate on the row selector inputs and delaying the output, is risky, because the row selector inputs may switch (say from 10111111 to 11011111) too fast for the intervening high to be registered. (In my own code, it can be less than one MCU cycle.) The simplest I can think of is one of those small MCUs, say an ATtiny404, with 8 inputs and 4 outputs, with the inputs level-shifted to 3.3V somehow. One of the outputs is the trigger strobe (indicating only one of the inputs is low and should be read now), with the three outputs indicating which input is low.(The hardware solution using an extra MCU can sound silly, unless you realize it is just programmable logic here, and not dependent on what kind of an MCU it is used with; its operation should be easy to verify with a scope alone.)

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 01, 2023, 06:51:39 am
content: Quote from: Nominal Animal on May 01, 2023, 04:45:21 amI try not to take things too personally especially on forums or expect too much from people either (see below.)Quote from: Nominal Animal on May 01, 2023, 04:45:21 amI get that, I try not to do this too often, but sometimes just being not too obvious actually is both "lean" and triggers interesting reactions.Quote from: Nominal Animal on May 01, 2023, 04:45:21 amSee, my unobvious smiley may have had some use.Regarding the OP's problem, your last post looks right. Unless we are missing some key information, the OP is just using a wrong software approach for the task at hand and is trying to make it work with some hardware.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 01, 2023, 07:31:30 am
content: Quote from: SiliconWizard on May 01, 2023, 03:34:39 amWhat, you guys really don't get it? To me it's obvious: the high-end microcontroller is probably there forsomething else. Why would anyone do an input matrix project which discards the inputs and does nothing with them?As we don't know what the complete project is about, it's quite safe to assume the high end microcontroller is there for some reason (even if not currently, it could be a learning project for something more complex in the future). And if so, the only sensible thing to do is to write software non-blocking, releasing the CPU time for those other tasks, just like Mr. Nominal suggests.Highly performant microcontrollers routinely combine performance-requiring parts and trivial parts. What is your suggestion, add another simpler MCU just to do the keyboard part with blocking delays, and then come up with MCU-to-MCU communication protocol? Sounds tedious and expensive.And for the OP, indeed you should not be thinking about HW (propagation delays, capacitances, whatnot). HW delays do not matter because humans and buttons are slow. That slowness should not be wasting your CPU time, though; you need to decouple the HW delays from CPU clock. This is a matter of writing software in the correct way. Periodic interrupts at 1kHz or so are a good start, but of course there are even more efficient ways.

author: brucehoult
author_rank: Super Contributor
timestamp: May 01, 2023, 07:41:05 am
content: Quote from: Siwastaja on May 01, 2023, 07:31:30 amOf course. And not expect physical moving systems with a resonant frequency of probably a few KHz to do sensible things at tens of nanosecond time scale.I think everyone except OP is in agreement on that.

author: Nominal Animal
author_rank: Super Contributor
timestamp: May 01, 2023, 09:01:19 am
content: Call me silly, but my own preference in this kind of case would be to create a logic interface to the external matrix, and then interface it to my microcontroller using UART over a digital isolator like ISO6721 (1/1) or ISO6742DWR (2/2).Looking at Mouser, ATtiny417 is around 1€ apiece, and can be programmed in C/C++ with the same toolchain (GCC or clang) as the MK66 and RT1062, although the backend is different (AVR instead of ARMv7e-m:Cortex-M4/M7). ISO6721BDR is 1.17€ in hundreds and 1.62€ in singles. For the 16 input signal lines, I'd use 0603 resistor arrays, 10k and 3.3k (isolated/separate), in voltage divider configuration (3.3/13.3≃0.248, 12V×3.3/(3.3+10)≃2.97V. With 5% resistors, the factor is 0.248±0.019.The trick is that I would power the ATtiny417 and ISO6742 from a power opamp output (total maximum current draw is about 20mA), input in a similar voltage divider configuration (making sure the input voltage won't exceed the supply voltage, after the dividers, taking into account the resistor variance), in unity buffer configuration. Perhaps TI TLV9301IDBVR, at about 0.50€.The main loop on the ATtiny417 would check the row selector inputs at regular intervals (basically the main loop is written around the row selector checking, with a delay to ensure minimum iteration interval). When the row selector inputs stabilize (only a specific one remains low for three consecutive main loop iterations), the column data inputs are checked, the matrix state updated accordingly, and applicable events sent.I personally would prefer UART for the communications if possible, because then the ATtiny could always send one byte per event: 0..63 for keypresses, 64..127 for autorepeats, and 192..255 for releases. This leaves 0xAA = 0b10101010 = 170 free for synchronization (although the ATtiny417 internal oscillator is 20MHz ± 2%), with code(c<128)indicating matrix key(c&63)press or autorepeat event. The other side of the UART could be used to requestNsync bytes, change key dead time, initial repeat delay, autorepeat interval, etc.Not only would the 12V keyboard matrix and its associated logic be electrically isolated from the MCU side, but this also makes the UART input on the MK66/RT1064 MCU an event queue, simplifying the main loop a lot. The UART interrupt is trivial, as it just stuffs the received byte into a circular buffer of sufficient size; and depending on what exactly the buttons are, can even discard the key releases if the duration of each keypress is not important.I'd also make it a separate unit from the main MCU: just switch that few-euro module if it burns out. The isolator ensures any oddness on the 12V side should be limited to that side, which helps with expensive MCUs like RT1064 (currently 20€+ in singles, 15€+ even in hundreds). I like the modularity here, and how using a secondary MCU simplifies the overall design, and even helps with repairability (considering the 12V keyboard matrix a glitchy black box).Nowyou are absolutely free to roll your eyes, even I am not sure if this suggestion would work! Again, I'm just a hobbyist, so I don't know whether this would make any business sense even if it does work; and I'm almost certainly missing things experienced EE's know to avoid here.

author: brucehoult
author_rank: Super Contributor
timestamp: May 01, 2023, 09:33:37 am
content: Quote from: Nominal Animal on May 01, 2023, 09:01:19 amRT1062 + 2 MB external flash + USB socket plus other stuff on a board for $20 = Teensy 4.0 :-)(I believe the RT1064 just has flash in the package)

author: Nominal Animal
author_rank: Super Contributor
timestamp: May 01, 2023, 10:04:03 pm
content: Yep, I have a few as you know, and I know luiHS has some too. (MK66 is used on Teensy 3.6 and RT1062 in Teensy 4.0, 4.1, and MicroMods. I don't have a 3.6, but I do have several of 4.0, one or two 4.1, and a MicroMod. And I really like them, and often recommend to people wanting to do either Arduinoy-stuff or bare metal development (without JTAG/debugging) but with more powerful microcontrollers.)All the prices I quited are from Mouser, as I mentioned. (I tried to use an apples-to-apples comparison regarding the prices.)Relatively speaking, my "silly" isolated ATtiny417 keyboard matrix handler will still be a fraction of the price of even a single RT1062; probably about half the price at 1k batches, but smaller fraction at smaller batches (maybe a quarter in singles).I am very curious about any comments on the approach. Especially using a power op-amp to provide a fractional supply voltage "feels" nifty, as it gives a nice working range for the actual 12V supply and I/O levels. Anything between 2.25 and 5.25 V for the ISO6721 and ATtiny417 will work just fine. High inputs need to be between 0.7×Vcc and 1.0×Vcc, so one might want to use 1% instead of 5% resistors in the dividers, just to keep things reliable.The isolator of course works as a level shifter: the other side supplies its own Vcc, determining the I/O levels on that side.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 02, 2023, 05:29:00 am
content: Well, anytime youneedisolation, it's tempting to simultaneously add task separation and move part of digital processing to a small, secondary MCU, because digital communication is usually way easier to isolate than the input signals (analog; or weird voltages; or just too many digital signals). I have nothing against your proposed solution; I would just hard-code those repetition rate etc. configurations to make the link unidirectional, one less signal to isolate, less code to write and test. Make the small MCU "do the right thing" out of box.Really the biggest hurdle to some is having to program those secondary MCUs. Especially if the software becomes non-trivial enough so that the full functionality can't be completely agreed upon and tested, so that firmware updates will be needed. But this key matrix thing shouldn't be that complex.