Sunday 17 February 2019

mosfet - AVR Pin Dual Use: Input and Output at (seemingly) the same time


I have been working on a few different versions of a bicycle light control circuit which reads in various buttons and sets various outputs accordingly such as headlight, taillight, blinkers, etc.


My current design is based around an ATtiny24 (Datasheet) using the internal oscillator (8MHz), programmed in C using AVR-GCC. I would like to keep external components such as shift registers to a minimum. Resistors are OK since they are cheap and small, and I am using MOSFETs (NTD4960N: Datasheet) to drive the LED banks.


Essentially, what I am looking to do is drive the MOSFETs with a 200Hz PWM signal to control the LED brightness, but limit the duty cycle to 90%. With that in mind, I would only need a pin to be an output for a maximum of 90% of the time. In the remaining 10% of the time, I want to switch the pin to an input to read the state of a button.


I tried a lot of various configurations to allow the MOSFET to stay OFF when it is supposed to be OFF, regardless of input from the button, and this is the best I could come up with:


MCU Dual Use I/O Pin



The supply voltage (VCC) is 5V, so when the button is pressed, about 0.9V is seen at the transistor gate. This is not enough for the transistor to start conducting, but it can be read by the MCU ADC which has been enabled using the internal 1.1V reference.


So the code drives the MOSFET with a 200Hz PWM signal. The duty cycle will vary with the desired LED brightness, but will not be greater than 90%. During the last 10% of the PWM cycle, the I/O pins are set as inputs (internal pullups disabled, digital input buffers disabled) and the ADC is used to read the state of the pin. The 10k resistor keeps the MOSFET off, and if a button is pressed, 0.9V is read by the ADC. This value is still not high enough to turn the MOSFET on, so the LEDs stay off, regardless of the button press.


Since the ADC is turned off and on, I discard the first reading and keep the second. This is done in plenty of time before the pin needs to be reset as an output to start the next PWM cycle. Since I am reading multiple buttons, I only read one each duty cycle, then update the ADC multiplxer to read the next button at the end of the next duty cycle - hence, each button is read once every [(# of buttons) * (200Hz)^-1]. The PWM and button reads are handled entirely by interrupts while MAIN determines what to do with the state of any particular button.


I have built and tested this circuit, and it seems to work perfectly, but I wanted to present the description here with the following questions:



  1. First, is this a bad idea? If so, then why?

  2. Is there an obviously better way to do this besides GPIO expanders/shift registers?


I can post some (or all) of the code if you want. I just thought the description might be enough, and I didn't want to make this any longer than it already was.


UPDATE



I should have said this the first time, but the MCU supply voltage (VCC) is 5V, the battery voltage (V_bat) is 12V (could be more like 14 on a fully charged battery), and the total LED current (as in the amount going through the FET) will be close to 2A. The LED bank will consist of numerous parallel strings of 3 series LEDs (white, V_LED = 3.3V) and a series resistor in each string. The pulsed current is around 50mA per string. With 40 or so strings equaling about 2A total.


I have tested and verified my ADC version of the circuit as well as the "digital" version presented by DrFriedParts below with a small current (50mA total), but have not yet tested either circuit with the larger current load.


This is the original project that I am redesigning. When I first built this bike light controller, I was new to microconctollers, so it was more of a learning experience than anything else.



Answer



That's perfectly fine...


The short answer is that there is nothing wrong with this approach. It presumes, of course, that you have time to switch and do an ADC conversion (which at 200Hz) you do.


You might want a series current-limiting resistor in line with the gate to protect your MCU driver (if the total gate charge of the N-FET is in the tens of nC, didn't read the datasheet).


If you want a completely "digital" solution:


schematic


simulate this circuit – Schematic created using CircuitLab



The component choices are (CircuitLab defaults) approximates, a wide range of parts will work, but it's a balancing act between R3 and R4.



  • You need to make the R3/R4 ratio big enough that V(R4) < M1's Vth

  • You need to make the R3/R4 ratio small enough that Vsrc-V(R3) > MCU V_IH


...for SW1 "on", MCU Hi-Z


Tuning


Here's a specific configuration that should work (5V source):


Materials:


See "documents" at these links:




Targets:


enter image description here


enter image description here


Procedure:


Start with the (GPIO: Hi-Z; SW1: Closed) case:



  1. Vsrc -> R3 -> D3 -> R4 -> GND, must yield V(R4) < Vth,M1,min = 2V

  2. We need V(gpio) > V_IH = 2.6V

  3. This spread determines the minimum Vf,diode (Vfd) we need



Now, look at the (GPIO: Logic-1; SW1: Open) case:



  1. We need V(R4) > Vth,M1,min = 1.8V (ideally with some comfortable margin)

  2. This determines the upper-bound of the required Vfd


Now, look at the (GPIO: Logic-1; SW1: Closed) case:



  1. We need I(R3) < I(OH),max

  2. This determines the minimum size of R3 (go bigger for reliability)



Example:



  • R3 = 15k

  • D3 = 1.6V (forward) = approx 3x 1N4148 in series

  • R4 = 10k


Control the FET/LED:


V(gpio) = 5V; V(g) = 3.4V




  • PASS: 3.4V > 2V -- FET turns "on"


Read the state of an "on" switch:


V(gpio) = 2.9V; V(g) = 1.4V



  • PASS: 1.4V < 1.8V -- FET turns "off"

  • PASS: 2.9V > 2.6V -- MCU reads logic 1


Avoid damaging contention:


Switch is "on" AND MCU is driving the GPIO "low"




  • PASS: 5V / R3 = 500uA


Power dissipation in the FET


The issue of power dissipation in the FET has been raised by a few commenters. It isn't a problem in this circuit due to the highly non-linear behavior of the LED.


Let's ignore the LED to bound the problem, by considering a worst-case impossible D4 with I(D4) = 20mA but Vled = 0 and R5 = 0 (impossible!). Now all of the power dissipation happens in the FET.


Under these conditions, the power dissipation in the FET can be maximally 100mW or ~1/5 of the maximum tolerable power of the suggested part. So we're safe.


However, you won't see dissipation near that level for any appreciable length of time. The transition time from R4 = 10k is approximately (RQV) = 10k * 1.1n * 3.4 = 37uS overall, but since we only need to move from 3.4V to below 1.8V we can finish in less than half that time.


At 200Hz, that translates into a mere 0.75% to 1.5% duty-cycle or less than 1mW in aggregate.


...and remember we ignored the real power consumers in the path -- the LED and current-limiting resistor (R5). In practice, it is impossible to deliver Vds = 5V to the FET, while Iled = 20mA, and the power dissipation in the FET will be negligible.



No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...