Thanh navigation

Thứ Năm, 11 tháng 8, 2022

Glossary Definition for Open-drain

 

Definition

An open-drain or open-collector output pin is driven by a single transistor, which pulls the pin to only one voltage (generally, to ground). When the output device is off, the pin is left floating (open, or hi-z). A common example is an n-channel transistor which pulls the signal to ground when the transistor is on or leaves it open when the transistor is off.

Open-drain refers to such a circuit implemented in FET technologies because the transistor's drain terminal is connected to the output; open-collector means a bipolar transistor's collector is performing the function.

When the transistor is off, the signal can be driven by another device or it can be pulled up or down by a resistor. The resistor prevents an undefined, floating state. (See the related term, hi-z.)

 https://www.maximintegrated.com/en/glossary/definitions.mvp/term/Open-drain/gpk/1174

 

Understand the I2C protocol in the context of firmware design and make your projects seamless.

 

Master the I2C protocol.

Supporting Information

The Typical Transaction

Devices communicating via I2C must conform to a specific sequence of events. Each event corresponds to a certain way of controlling the clock (SCL) and data (SDA) lines; as discussed in the “Supporting Information” articles listed above, these two signals are the only means by which devices on the bus can share information. We will refer to one communication sequence as a “transaction”; this word is more appropriate than “transmission” because every transaction involves both transmitted data and received data, though in some cases the only received data is an acknowledge (ACK) or not-acknowledge (NACK) bit detected by the master. The following timing diagram shows a typical I2C transaction.

Note the following:

  • The dotted line corresponding to the logic-high portion of the clock reminds us that logic high (for both SCL and SDA) is the “recessive” state—in other words, the signal naturally floats up to logic high via the pull-up resistor. The “dominant” state is logic low, because the signal will be low only when a device is actually driving it low.
  • The transaction begins with a “start bit.” Every I2C transaction must begin with a start bit, which is defined as a falling edge on SDA while SCL is logic high.
  • The transaction ends with a “stop bit,” defined as a rising edge on SDA while SCL is logic high. I2C transactions must end with a stop bit; however, as discussed later in the article, multiple start bits can occur before a stop bit is generated.
  • Data is valid while the clock is high and changes state while the clock is low; digital communication systems are usually edge-driven, so in practice the data is read on the rising edge of the clock and updated on the falling edge of the clock.
  • Information is exchanged one-byte-at-a-time, starting with the most significant bit, and each byte is followed by an ACK or NACK.
  • You might expect ACK to be indicated by logic high and NACK to be indicated by logic low, but this is not the case. ACK is logic low and NACK is logic high. This is necessary because high is the recessive state—if the slave is nonfunctional, the signal naturally floats up to a NACK. Likewise, ACK (indicated by the dominant logic low) can be transmitted only if the device is operational and ready to continue with the transaction.

The following list describes the sequence of events in the above transaction:

  1. The master generates a start bit to initiate the transaction.
  2. The master transmits the 7-bit address corresponding to the slave with which it wants to communicate.
  3. The final bit in the first one-byte segment is the read/write indicator. The master sets this bit to logic high if it wants to read data from the slave, or to logic low if it wants to write data to the slave.
  4. The next byte is the first data byte. This comes from either the master or the slave, depending on the state of the read/write bit. As usual, we have 8 bits of data, starting with the most significant bit.
  5. The data byte is followed by an ACK or a NACK, generated by the master if this is a read transaction or by the slave if this is a write transaction. ACK and NACK can mean different things depending on the firmware or low-level-hardware design of the communicating devices. For example, the master could use NACK to say “this is the last data byte,” or if the slave knows how much data to send, it could use ACK to confirm that the data was successfully received.
  6. The transaction is terminated with a stop bit generated by the master.

How Many Bytes?

Every transaction begins the same way: start bit, address, read/write, ACK/NACK. After that, any number of bytes can be sent from master to slave or from slave to master, with each byte followed by ACK or NACK. NACK can be useful as a way to say “stop sending data!” For example, the master might want to receive a continuous stream of data from a slave device (such as a temperature sensor); each byte would be followed by ACK, and if the master needs to turn its attention to something else, it can NACK the slave and begin a new transaction whenever it is ready.

Start without a Stop

The I2C protocol allows for something called a “repeated start” condition. This occurs when the master initiates a transaction with a start bit then initiates a new transaction via another start bit without an intervening stop bit, as follows:

This feature can be used whenever a single master needs to perform two or more separate transactions. However, there is a situation in which the repeated start condition is particularly handy:

Let’s say you have a slave device that stores information in a bank of registers. You want to retrieve data from register address 160, 0xA0 in hex. The I2C protocol does not allow the master to send data and receive data in a single transaction. Consequently, you have to perform a write transaction to specify the register address and then a separate read transaction to retrieve the data. This approach can lead to problems, though, because the master releases the bus at the end of the first transaction, and thus another master could claim the bus and prevent the first master from getting the data it needs. Furthermore, the second master might communicate with the same slave and specify a different register address . . . if the first master then claims the bus and reads data without re-specifying the register address, it will read the wrong data! If the second master then tries to perform the read transaction in its write-then-read procedure, it also will end up with the wrong data! This is a system failure waiting to happen—fortunately, the repeated start condition can prevent this mess by initiating the second (read) transaction without releasing the bus:

When Masters Can’t Get Along

Part of what makes I2C so versatile is its support for multiple masters. But as the previous section demonstrates, masters don’t always play well together. A device’s I2C logic must be able to determine if the bus is free; if another master has claimed the bus, the device waits until the current transaction concludes before initiating its own transaction. But what happens when two (or more) masters attempt to initiate a transaction at the same time? I2C provides an effective and surprisingly simple solution to this otherwise irksome problem. The process is referred to as “arbitration,” and it relies upon the flexibility of I2C’s open-drain bus configuration: if one master attempts to drive the signal logic high and the other attempts logic low, the logic-low master will “win,” and furthermore, the “loser” can detect that the actual output state is not the intended output state:

This diagram conveys the basis of I2C arbitration; the process occurs as follows:

  1. Both masters generate a start bit and proceed with their transmissions.
  2. If the masters happen to choose the same logic levels, nothing happens.
  3. As soon as the masters attempt to impose different logic levels, the master driving the signal low is proclaimed the winner; the loser detects the logic mismatch and abandons its transmission.

Take a moment to appreciate the simplicity and efficacy of this arrangement:

  • The winner continues its transmission without interruption—no corrupted data, no driver contention, no need to restart the transaction.
  • Theoretically the loser could monitor the slave address during the arbitration process and actually make a proper response if it happens to be the addressed slave.
  • If the competing masters are both requesting data from the same slave, the arbitration process does not unnecessarily interrupt either transaction—no mismatch will be detected, and the slave will output its data to the bus such that multiple masters can receive it.

Conclusion

This article has covered the prominent I2C details that influence the design of firmware or low-level hardware. If your microcontroller includes dedicated I2C or SMBus hardware, some of the implementation details will be handled automatically. This is convenient but certainly not an excuse for ignorance because you will still need to know at least a little bit (probably more than a little bit) about how I2C really works. Furthermore, if you ever find yourself stranded on a desert island without an I2C peripheral, the information presented here will put you well on your way to designing a firmware-only (aka “bit-banging”) I2C routine.

The I2C Bus: Firmware Implementation Details

 

Understand the I2C protocol in the context of firmware design and make your projects seamless. 

Master the I2C protocol.

Supporting Information

The Typical Transaction

Devices communicating via I2C must conform to a specific sequence of events. Each event corresponds to a certain way of controlling the clock (SCL) and data (SDA) lines; as discussed in the “Supporting Information” articles listed above, these two signals are the only means by which devices on the bus can share information. We will refer to one communication sequence as a “transaction”; this word is more appropriate than “transmission” because every transaction involves both transmitted data and received data, though in some cases the only received data is an acknowledge (ACK) or not-acknowledge (NACK) bit detected by the master. The following timing diagram shows a typical I2C transaction.

Note the following:

  • The dotted line corresponding to the logic-high portion of the clock reminds us that logic high (for both SCL and SDA) is the “recessive” state—in other words, the signal naturally floats up to logic high via the pull-up resistor. The “dominant” state is logic low, because the signal will be low only when a device is actually driving it low.
  • The transaction begins with a “start bit.” Every I2C transaction must begin with a start bit, which is defined as a falling edge on SDA while SCL is logic high.
  • The transaction ends with a “stop bit,” defined as a rising edge on SDA while SCL is logic high. I2C transactions must end with a stop bit; however, as discussed later in the article, multiple start bits can occur before a stop bit is generated.
  • Data is valid while the clock is high and changes state while the clock is low; digital communication systems are usually edge-driven, so in practice the data is read on the rising edge of the clock and updated on the falling edge of the clock.
  • Information is exchanged one-byte-at-a-time, starting with the most significant bit, and each byte is followed by an ACK or NACK.
  • You might expect ACK to be indicated by logic high and NACK to be indicated by logic low, but this is not the case. ACK is logic low and NACK is logic high. This is necessary because high is the recessive state—if the slave is nonfunctional, the signal naturally floats up to a NACK. Likewise, ACK (indicated by the dominant logic low) can be transmitted only if the device is operational and ready to continue with the transaction.

The following list describes the sequence of events in the above transaction:

  1. The master generates a start bit to initiate the transaction.
  2. The master transmits the 7-bit address corresponding to the slave with which it wants to communicate.
  3. The final bit in the first one-byte segment is the read/write indicator. The master sets this bit to logic high if it wants to read data from the slave, or to logic low if it wants to write data to the slave.
  4. The next byte is the first data byte. This comes from either the master or the slave, depending on the state of the read/write bit. As usual, we have 8 bits of data, starting with the most significant bit.
  5. The data byte is followed by an ACK or a NACK, generated by the master if this is a read transaction or by the slave if this is a write transaction. ACK and NACK can mean different things depending on the firmware or low-level-hardware design of the communicating devices. For example, the master could use NACK to say “this is the last data byte,” or if the slave knows how much data to send, it could use ACK to confirm that the data was successfully received.
  6. The transaction is terminated with a stop bit generated by the master.

How Many Bytes?

Every transaction begins the same way: start bit, address, read/write, ACK/NACK. After that, any number of bytes can be sent from master to slave or from slave to master, with each byte followed by ACK or NACK. NACK can be useful as a way to say “stop sending data!” For example, the master might want to receive a continuous stream of data from a slave device (such as a temperature sensor); each byte would be followed by ACK, and if the master needs to turn its attention to something else, it can NACK the slave and begin a new transaction whenever it is ready.

Start without a Stop

The I2C protocol allows for something called a “repeated start” condition. This occurs when the master initiates a transaction with a start bit then initiates a new transaction via another start bit without an intervening stop bit, as follows:

This feature can be used whenever a single master needs to perform two or more separate transactions. However, there is a situation in which the repeated start condition is particularly handy:

Let’s say you have a slave device that stores information in a bank of registers. You want to retrieve data from register address 160, 0xA0 in hex. The I2C protocol does not allow the master to send data and receive data in a single transaction. Consequently, you have to perform a write transaction to specify the register address and then a separate read transaction to retrieve the data. This approach can lead to problems, though, because the master releases the bus at the end of the first transaction, and thus another master could claim the bus and prevent the first master from getting the data it needs. Furthermore, the second master might communicate with the same slave and specify a different register address . . . if the first master then claims the bus and reads data without re-specifying the register address, it will read the wrong data! If the second master then tries to perform the read transaction in its write-then-read procedure, it also will end up with the wrong data! This is a system failure waiting to happen—fortunately, the repeated start condition can prevent this mess by initiating the second (read) transaction without releasing the bus:

When Masters Can’t Get Along

Part of what makes I2C so versatile is its support for multiple masters. But as the previous section demonstrates, masters don’t always play well together. A device’s I2C logic must be able to determine if the bus is free; if another master has claimed the bus, the device waits until the current transaction concludes before initiating its own transaction. But what happens when two (or more) masters attempt to initiate a transaction at the same time? I2C provides an effective and surprisingly simple solution to this otherwise irksome problem. The process is referred to as “arbitration,” and it relies upon the flexibility of I2C’s open-drain bus configuration: if one master attempts to drive the signal logic high and the other attempts logic low, the logic-low master will “win,” and furthermore, the “loser” can detect that the actual output state is not the intended output state:

This diagram conveys the basis of I2C arbitration; the process occurs as follows:

  1. Both masters generate a start bit and proceed with their transmissions.
  2. If the masters happen to choose the same logic levels, nothing happens.
  3. As soon as the masters attempt to impose different logic levels, the master driving the signal low is proclaimed the winner; the loser detects the logic mismatch and abandons its transmission.

Take a moment to appreciate the simplicity and efficacy of this arrangement:

  • The winner continues its transmission without interruption—no corrupted data, no driver contention, no need to restart the transaction.
  • Theoretically the loser could monitor the slave address during the arbitration process and actually make a proper response if it happens to be the addressed slave.
  • If the competing masters are both requesting data from the same slave, the arbitration process does not unnecessarily interrupt either transaction—no mismatch will be detected, and the slave will output its data to the bus such that multiple masters can receive it.

Conclusion

This article has covered the prominent I2C details that influence the design of firmware or low-level hardware. If your microcontroller includes dedicated I2C or SMBus hardware, some of the implementation details will be handled automatically. This is convenient but certainly not an excuse for ignorance because you will still need to know at least a little bit (probably more than a little bit) about how I2C really works. Furthermore, if you ever find yourself stranded on a desert island without an I2C peripheral, the information presented here will put you well on your way to designing a firmware-only (aka “bit-banging”) I2C routine.

 

Introduction to the I2C Bus

 

This article covers the essential characteristics and prominent advantages of the Inter–Integrated Circuit (aka I2C) serial-communications protocol. 

This article covers the essential characteristics and prominent advantages of the inter–integrated circuit (AKA I2C) serial-communications protocol.

Communication Between Components: Communication Protocols

It should come as no surprise that a common feature of electronic systems is the need to share information among two or three or ten separate components.

Engineers have developed a number of standard protocols that help different chips communicate successfully—a fact that becomes apparent when you confront the barrage of acronyms under “communications” in the list of features for a microcontroller or digital signal processor: UART, USART, SPI, I2C, CAN. . . . Each protocol has its pros and cons, and it is important to know a little about each one so that you can make an informed decision when choosing components or interfaces.

This article is about I2C, which is typically used for communications between individual integrated circuits located on the same PCB. Two other common protocols that also fit into this general category are UART (Universal Asynchronous Receiver/Transmitter) and SPI (Serial Peripheral Interface). You need to know the basic characteristics of I2C before you can thoroughly understand a comparison between these three interfaces, so we will discuss that topic at the end of this article.

What Is the I2C Bus?

I2C stands for inter–integrated circuit bus. There is no doubt, though, that the I2C protocol suffers from a serious terminology problem. The most straightforward—and probably the least common—abbreviation is IIC. Perhaps this abbreviation has been disdained because the two capital I’s look like two 1s, or two lowercase l’s, or Roman numeral II, or the symbol for parallel resistors. . . . In any event, the abbreviation I2C (spoken as “I squared C”) gained popularity, despite the questionable logic of treating a normal letter as if it is a variable subject to exponentiation. The third option is I2C (“I two C”), which avoids the inconvenience of superscript formatting and is also somewhat easier to pronounce than “I squared C.”

The final layer of fog settles in when you notice that SMB or SMBus is apparently used as yet another way of referring to the I2C bus. Actually, these abbreviations refer to the System Management Bus, which is distinct from, though almost identical to, the I2C bus. The original I2C protocol was developed by Phillips Semiconductor, and years later Intel defined the SMBus protocol as an extension of I2C. The two buses are largely interchangeable; if you are interested in the minor differences between them, refer to page 57 of the System Management Bus Specification.

Like Trying to Have an Important Conversation in a Room Full of People

To appreciate the clever techniques that make I2C so effective, you need to think about the difficulty of achieving reliable yet versatile communication between multiple independent components. The situation is simple enough if you have one chip that is always the master and one chip that is always the slave.

But what if you have multiple slaves? What if the slaves don’t know who the master is? What if there are multiple masters? What happens if a master requests data from a slave that for some reason has become nonfunctional? Or what if the slave becomes nonfunctional in the middle of a transmission? What if a master claims the bus to make a transmission then crashes before releasing the bus?

 

The point is, there are a lot of things that can go wrong in this sort of communication environment. You have to keep this in mind when you are learning about I2C because, otherwise, the protocol will seem insufferably complicated and finicky. The fact is, this extra complexity is what allows I2C to provide flexible, extensible, robust, low-pin-count serial communication.

Overview of I2C Communication

Before we get into any details, here are the key characteristics of I2C:

 

 

  • Only two signals (clock and data) are used, regardless of how many devices are on the bus.
  • Both signals are pulled up to a positive power supply voltage through appropriately sized resistors.
  • Every device interfaces to the clock and data signal through open-drain (or open-collector) output drivers.
  • Each slave device is identified by means of a 7-bit address; the master must know these addresses in order to communicate with a particular slave.
  • All transmissions are initiated and terminated by a master; the master can write data to one or more slaves or request data from a slave.
  • The labels “master” and “slave” are inherently non-permanent: any device can function as a master or slave if it incorporates the necessary hardware and/or firmware. In practice, though, embedded systems often adopt an architecture in which one master sends commands to or gathers data from multiple slaves.
  • The data signal is updated on the falling edge of the clock signal and sampled on the rising edge, as follows:

 

 

  • Data is transferred in one-byte sections, with each byte followed by a one-bit handshaking signal referred to as the ACK/NACK (acknowledge or not-acknowledge) bit.

What Are the Advantages of I2C? I2C vs UART vs SPI

The advantages of I2C can be summarized as follows:

  • maintains low pin/signal count even with numerous devices on the bus
  • adapts to the needs of different slave devices
  • readily supports multiple masters
  • incorporates ACK/NACK functionality for improved error handling

And here are some disadvantages:

  • increases the complexity of firmware or low-level hardware
  • imposes protocol overhead that reduces throughput
  • requires pull-up resistors, which
    • limit clock speed
    • consume valuable PCB real estate in extremely space-constrained systems
    • increase power dissipation

We can see from these points that I2C is especially suitable when you have a complicated, diverse, or extensive network of communicating devices. UART interfaces are generally used for point-to-point connections because there is no standard way of addressing different devices or sharing pins. SPI is great when you have one master and a few slaves, but each slave requires a separate “slave select” signal, leading to high pin count and routing difficulties when numerous devices are on the bus. And SPI is awkward when you need to support multiple masters.

You may need to intentionally avoid I2C if throughput is a dominant concern; SPI supports higher clock frequencies and minimizes overhead. Also, the low-level hardware design for SPI (or UART) is much simpler, so if you are working with an FPGA and developing your serial interface from scratch, I2C should probably be considered a last resort.

Conclusion

We have presented the salient characteristics of I2C, and we now know enough about the protocol’s pros and cons to allow for an informed decision on which serial bus you might choose for a given application. In future articles we will explore the protocol, and how to actually implement it, in more detail.

Further Reading

 

The I2C Bus: Hardware Implementation Details

 

 

Sometimes a Little Complexity Is a Good Thing

The I2C protocol is notable for some less-than-straightforward characteristics: You don’t just connect a few IC pins together and then let the low-level hardware take over as you read from or write to the appropriate buffer, as is more or less the case with SPI (Serial Peripheral Interface) or a UART (Universal Asynchronous Receiver/Transmitter). But I2C’s complexity is not without purpose; the rest of this article will help you to understand the somewhat nuanced hardware implementation details that make I2C such a versatile and reliable option for serial communication among multiple independent ICs.

The Open Drain

A defining characteristic of I2C is that every device on the bus must connect to both the clock signal (abbreviated SCL) and the data signal (abbreviated SDA) via open-drain (or open-collector) output drivers. Let’s take a look at what this actually means. First consider the typical CMOS (inverting) output stage:

If the input is logic high, the NMOS transistor is on and the PMOS transistor is off. The output thus has a low-impedance connection to ground. If the input is logic low, the situation is reversed, and the output has a low-impedance connection to VDD. This is referred to as a push-pull output stage, though this name is not particularly informative because it does not emphasize the low-impedance nature of the connections that control the output. In general, you cannot directly connect two push-pull outputs because current will flow freely from VDD to ground if one is logic high and the other is logic low.

Now consider the open-drain output configuration:

The PMOS transistor has been replaced by a resistor external to the IC. If the input is logic high, the NMOS transistor provides a low-impedance connection to ground. But if the input is logic low, the NMOS looks like an open circuit, which means that the output gets pulled up to VDD through the external resistor. This arrangement leads to two important differences. First, nontrivial power consumption occurs when the output is logic low, because current flows through the resistor, through the channel of the NMOS transistor, to ground (in the push-pull configuration, this current is blocked by the high impedance of the off-state PMOS transistor). Second, the output signal behaves differently when it is logic high because it is connected to VDD through a much higher resistance (usually at least 1 kΩ). This feature makes it possible to directly connect two (or more) open-drain drivers: even if one is logic low and the other is logic high, the pull-up resistor ensures that current does not flow freely from VDD to ground.

Here are three important implications of this open-drain bus configuration:

  • The signals always default to logic high. For example, if an I2C master tries to communicate with a slave device that has become nonfunctional, the data signal never enters an undefined state. If the slave is not driving the signal, it will be read as logic high. Likewise, if a master device loses power during the middle of a transmission, the SCL and SDA will return to logic high. Other devices can determine that the bus is available for new transmissions by observing that both SCL and SDA have been logic high for a certain amount of time.
  • Any device on the bus can safely drive the signals to logic low, even if another device is trying to drive them high. This is the basis of I2C’s “clock synchronization” or “clock stretching” feature: the master generates the serial clock, but if necessary a slave device can hold SCL low and thereby decrease the clock frequency.
  • Devices with different supply voltages can coexist on the same bus, as long as the lower-voltage devices will not be damaged by the higher voltage. For example, a 3.3 V device can communicate with a 5 V device if SCL and SDA are pulled up to 5 V—the open-drain configuration causes the logic-high voltage to reach 5 V, even though the 3.3 V device cannot drive 5 V from a typical push-pull output stage.

If You Have R, You Have RC

The open-drain output driver is by no means the standard configuration among digital ICs, and with good reason: it comes with some significant disadvantages. One of these disadvantages becomes apparent when we recall that capacitance is everywhere. Voltage changes are constrained by the time required to charge or discharge the capacitance associated with a particular node. The trouble is, the pull-up resistors on SCL and SDA limit the amount of charging current—in other words, we have much more R in the RC time constant that governs the transition from logic low to logic high.

 

 

As these diagrams indicate, the low-to-high transition will be significantly slower than the high-to-low transition, resulting in the classic I2C “sawtooth” waveforms:

These two scope captures show the low-to-high and high-to-low transition for an I2C clock signal with a 1 kΩ pull-up resistor and minimal capacitance (only two devices on the bus, with short PCB traces).

How to Size the Pull-Up Resistors

At this point it should be apparent that the pull-up resistance imposes limitations on the maximum clock frequency of a particular I2C bus. Actually, both resistance and capacitance are factors here, though we have little control over capacitance because it is determined primarily by how many devices are on the bus and the nature of the interconnections between these devices. This leads to the enduring question, “What value of pull-up resistor should I use?” The trade-off is speed vs. power dissipation: lower resistance reduces the RC time constant but increases the amount of current that flows from VDD to ground (through the pull-up resistor) whenever SCL or SDA is logic low.

The official I2C specification (page 9) states that a voltage is not considered “logic high” until it reaches 70% of VDD. You may recall that the RC time constant tells us how long it will take a voltage to reach approximately 63% of the final voltage. Thus, for simplicity we will assume that R×C tells us how long it will take the signal to rise from a voltage near ground potential to the logic-high voltage.

Now how do we find the capacitance? The “easy” way is to assemble the entire system and measure it; at least, this is probably easier than trying to perform an accurate calculation that accounts for every source of capacitance—as an app note from Texas Instruments expresses it, “in the normal construction of electrical circuits, an unimaginable number of capacitors are formed.” If the measurement approach is not an option (as is often the case), you can make a rough estimate by finding the pin capacitance for each device on the bus (hopefully the datasheet doesn’t let you down here) and then adding 3 pF per inch of PCB trace and 30 pF per foot of coaxial cable (these numbers are from the same app note, page 3).

Let’s say we have 50 pF of bus capacitance and we want to obey the I2C “standard mode” specifications, which state that the maximum rise time is 1000 ns.

So you can satisfy the spec with Rpull-up = 20 kΩ; this value also gives you the minimum power consumption. What about speed? Let’s say you want the clock-high time to be at least triple the rise time.

If 167 kHz isn’t fast enough, you can lower the resistance (at the cost of increased power consumption) until you reach your desired clock speed. (Actually, “standard mode” limits the clock speed to 100 kHz, but you can adapt these specs to the needs of your system.)

These are rough calculations, but honestly, you don’t need to stress out about finding the perfect resistance. This general approach can help you to settle on a reasonable value, and you can always swap in different resistors if something isn’t working the way you want.

Conclusion

If this article has served its purpose, you are now thoroughly familiar with the salient details involved in I2C hardware design. We will look at firmware implementation in a separate article

 

Link: https://www.allaboutcircuits.com/technical-articles/the-i2c-bus-hardware-implementation-details/

Why do I2C pins have to be open-drain and not push-pull?

 

Question Why do I2C pins have to be open-drain and not push-pull? Answer Setting the I2C pins to push-pull can cause damage to the devices on the bus. The reason this is an issue is that

Details

Question

Why do I2C pins have to be open-drain and not push-pull?

Answer

Setting the I2C pins to push-pull can cause damage to the devices on the bus. The reason this is an issue is that there are three parts of the I2C communication protocol specifically that can result in a direct short from power to ground:

  • Bus arbitration if there is more than one master on the bus
  • Slave clock stretching
  • ack/nack

In these above three scenarios, it is possible for one device to be driving SDA high, while another device on the bus is driving SDA low. If the outputs are open-drain, devices can only drive low, or float (pulled-up in the case of I2C). In the above three scenarios, this means there is no conflict since the device driving low will always win on the bus.

If the outputs are push-pull, then the only two possible states are drive low or drive high; there is no "float" state. In the above three scenarios with push-pull outputs, one device on the bus will be driving SDA low, and another will be driving SDA high, so there will be a direct short between power and ground through the two devices. This can cause damage to the devices and is not recommended.

Link: https://community.silabs.com/s/article/why-do-i2c-pins-have-to-be-open-drain-and-not-push-pull-x?language=en_US

 

Thứ Ba, 9 tháng 8, 2022

16×2 lcd in 4-bit and 8-bit mode (LCD: Part 3)

 After making many microcontroller projects with character lcd’s(16×1,16×2) and interfacing them with variety of microcontrollers (arduino, microchip pin microcontroller,8051 series,stm32 etc). I still get emails from students about what is the difference between character lcd interfacing in 4-bit and 8-bit mode. So i decided why not to write a post on difference between lcd 4-bit and 8-bit mode interfacing. 

In this short tutorial i will try to explain the basic difference between the two modes and the advantages/disadvantages in using the either of the two. This post will help the newbies putting their step in embedded field to easily understand the two modes. Character lcd’s come in many sizes 8×1 , 8×2 , 10×2 , 16×1 , 16×2 , 16×4 , 20×2 , 20×4 ,24×2 , 30×2 , 32×2 , 40×2 etc. Each character lcd has 8-bit data port to connect with external controllers.  All the character lcds can be used in 8-bit as well as 4-bit mode.

I assume that you have an introduction to character lcds and know about their internal structure, pin out, registers, commands etc. If you don’t I recommend to first take the introduction tutorial and then resume with this post.

lcd 4bit and 8bit mode – Major difference

The major difference in 4 bit and 8 bit mode lies in data pins used and lcd initializing commands.

Since character lcd’s has 8 data pins so they accept only 8-bit data. Character datatype is 8-bit wide. So character values can easily be send to lcd. This mode is know as 8-bit mode in which we send an 8-bit value such as character or ASCII value to lcd. 

In 4 bit mode only four data pins are used. Character 8-bit ASCII value is divided in to two 4-bit nibbles. High nibble is sent first following by the lower nibble. So in theory two strokes are needed to send a character(8-bit) to lcd when we are using lcd in 4-bit mode. 

In contrast in 8-bit communication mode, 8-bit ASCII value of character is send in a single stroke to lcd.

Thus the 4-bit mode generates latency. Although 4-bit mode generates latency it on the other hand saves 4 gpio(general purpose input out pins) of the external controller sending data to lcd. Which can be utilized else where.   

The gif animation below explains the difference between 4-bit and 8-bit mode very beautifully.

16x2 lcd in 4 bit and 8 bit mode with microcontroller

16×2 lcd in 4 bit and 8 bit mode with microcontroller

Lcd in 4-bit mode

Commands used to initialize the 4-bit lcd mode 

  • To initialize character lcd in 4 bit mode we send value hex 0x20 to command register of lcd. 0x20 tells the lcd controller that we want to communicate in 4-bit mode. Lcd is 1 line (has 1 row) and we want character shape displayed in 5×7 matrix.
  • If our character lcd has 2 lines (rows) we will send 0x28 instead of 0x20. It tells the lcd controller that we want 4 bit communication and character size is between 5×7 dot matrix.
  • 4-bit mode make use of only just four data pins D4-D5-D6-D7.
  • In 4-bit mode character is displayed on lcd in two pulse signals. First the higher four nibbles of a character are sent to the lcd with an enable stroke. Than the lower four nibbles are send with enable stroke.
  • Since two pulse (enable) signals are required to display a single character so 4-bit mode latency time is high.

Some Projects made using character lcd in 4-bit mode.

Lcd in 8-bit mode

Commands used to initialize the 8-bit lcd mode are

  • To initialize character lcd in 8-bit mode we send vale hex 0x30 to command register of lcd. 0x30 tells lcd that we want to communicate in 8-bit mode. Lcd is 1 line (has 1 row) and we want character shape displayed in 5×7 matrix. 
  • If our character lcd has 2 lines (rows) we will send 0x38 instead of 0x20. It tells the lcd controller that we want 4 bit communication and character size is between 5×7 dot matrix.
  • In 8-bit mode only one pulse signal is required to display a character on lcd.
  • Thus it is faster than 4-bit mode.

Some Projects made using character lcd in 8-bit mode.

  https://www.engineersgarage.com/lcd-in-4-bit-mode-and-8-bit-mode/

16×2 lcd working and internal structure (LCD: Part 0)

 

NxN(8×1 , 8×2 , 10×2 , 16×1 , 16×2 , 16×4 , 20×2 , 20×4 ,24×2 , 30×2 , 32×2 , 40×2) Character lcd working, Pinout and description
 
Lcd stands for liquid crystal display. Character and graphical lcd’s are most common among hobbyist and diy electronic circuit/project makers. Since their interface serial/parallel pins are defined so its easy to interface them with many microcontrollers. Many products we see in our daily life have lcd’s with them. They are used to show status of the product or provide interface for inputting or selecting some process. Washing machine, microwave,air conditioners and mat cleaners are few examples of products that have character or graphical lcd’s installed in them. In this tutorial i am going to discuss about the character lcd’s. How they work? their pin out and initialization commands etc.

Lcd sizes

​Character lcd’s come in many sizes 8×1, 8×2, 10×2, 16×1, 16×2, 16×4, 20×2, 20×4, 24×2, 30×2, 32×2, 40×2 etc . Many multinational companies like Philips, Hitachi, Panasonic make their own custom type of character lcd’s to be used in their products. All character lcd’s performs the same functions(display characters numbers special characters, ascii characters etc).Their programming is also same and they all have same 14 pins (0-13) or 16 pins (0 to 15). 
In an mxn lcd. M denotes number of columns and n represents number of rows. Like if the lcd is denoted by 16×2 it means it has 16 columns and 2 rows. Few examples are given below. 16×2, 8×1 and 8×2 lcd are shown in the picture below. Note the difference in the rows and columns.
 
16x2 Character Lcd Rows and Coulombs

16×2 Character Lcd Rows and Colulmns
8x1 Character Lcd Rows and Coulombs

 8×1 Character Lcd Rows and Columns

8x2 Character Lcd Rows and Coulombs 

8×2 Character Lcd Rows and Columns

How character is made on lcd?

On a character lcd a character is generated in a matrix of 5×8 or 5×7. Where 5 represents number of columns and 7/8 represent number of rows. Maximum size of the matrix is 5×8. You can not display character greater then 5×8 dimension matrix. Normally we display a character in 5×7 matrix and left the 8th row for the cursor. If we use the 8th row of the matrix for the character display, then their will be no room for cursor. The picture below shows the 5×8 dot matrix pixels arrangement.

16x2 lcd single character rows and coulombs

16×2 lcd single character rows and columns

 

To display character greater than this dimension you have to switch to graphical lcd’s. To learn about graphical lcds here is a good tutorial Graphical Lcd’s Working and Pin out.

Lcd 16×2 Pin out

All character lcd’s have 

  • Eight(8) data pins D0-D7
  • Vcc (Apply +5 volt here)
  • Gnd (Ground this pin)
  • Rc (Register select)
  • Rw (read – write)
  • En (Enable)
  • V0 (Set Lcd contrast)

16×2 lcd pin out diagrammatically is shown below. 

16x2 lcd pinout 

16×2 lcd pinout
The picture above shows the pin out of the character lcd. Almost all the character lcd’s are composed of the same pin out. Lcd’s with total pin count equal to 14 does not have back light control option. They might have back light always on or does not have a back light. 16 total pin count lcd’s have 2 extra A and K pins. A means anode and K cathode, use these pins to control the back light of lcd.

Character lcd controller – HD44780

Character Lcd’s have a controller build in to them named HD44780. We actually talk with this controller in order to display character on the lcd screen. HD44780 must be properly handled and initialized before sending any data to it. HD44780 has some registers which are initialized and  manipulated for character displaying on the lcd. These registers are selected by the pins of character lcd. 

Lcd Rs(Register select) Pin

Register select selects the HD44780 controller registers. It switches between Command and data register.                      

  • Command Register
  • Data Register
Command Register
When we send commands to lcd these commands go to Command register and are processed their. Commands with their full description are given in the picture below. When Rs=0 command register is selected.
Data Register
When we send Data to lcd it goes to data register and is processed their. When Rs=1 data register is selected.

Lcd RW(Read/Write) Pin

Rw pin is used to read and write data to HD44780 data and command registers. When Rw=1 we can read data from lcd. When Rw=0 we can write to lcd.

Lcd En(Enable) Pin

When we select the register Rs(Command and Data) and set Rw(read –  write) and placed the raw value on 8-data lines, now its time to execute the instruction. By instruction i mean the 8-bit data or 8-bit command present on Data lines of lcd. For sending the final data/command present on the data lines we use this enable pin. Usually it remains en=0 and when we want to execute the instruction we make it high en=1 for some mills seconds. After this we again make it ground en=0.

Lcd V0 of contrast set pin

To set lcd display sharpness use this pin. Best way is to use variable resistor such as potentiometer a variable current makes the character contrast sharp. Connect the output of the potentiometer to this pin. Rotate the potentiometer knob forward and backward to adjust the lcd contrast. 
NOTE: we can not send an integer, float, long, double type data to lcd because lcd is designed to display a character only. Only the characters that are supported by the HD44780 controller. See the HD44780 data sheet to find out what characters can we display on lcd.  The 8 data pins on lcd carries only  Ascii 8-bit code of the character to lcd. How ever we can convert our data in character type array and send one by one our data to lcd. Data can be sent using lcd in 8-bit or 4-bit mode. If 4-bit mode is used, two nibbles of data (First high four bits and then low four bits) are sent to complete a full eight-bit transfer. 8-bit mode is best used when speed is required in an application and at least ten I/O pins are available. 4-bit mode requires a minimum of seven bits. In 4-bit mode, only the top 4 data pins (4-7) are used. 

Standard Lcd Commands with their functions are described below.

nxn lcd initialization commands 

 nxn lcd initialization commands

Command 0x30 means we are setting 8-bit mode lcd having 1 line and we are initializing it to be 5×7 character display.Now this 5×7 is some thing which every one should know what it stands for. usually the characters are displayed on lcd in 5×8 matrices form. where 5 is total number of columns and is number of rows.Thus the above 0x30 command initializes the lcd to display character in 5 columns and 7 rows the last row we usually leave for our cursor to move or blink etc.

Lcd command meanings and functions

  • The command 0x38 means we are setting 8-bit mode lcd having two lines and character shape between 5×7 matrix.
  • The command 0x20 means we are setting 4-bit mode lcd having 1 line and character shape between 5×7 matrix.
  • The command 0x28 means we are setting 4-bit mode lcd having 2 lines and character shape between 5×7 matrix.
  • The command 0x06 is entry mode it tells the lcd that we are going to use.
  • The command 0x08 dispalys cursor off and display off but with out clearing DDRAM contents.
  • The command 0x0E displays cursor on and dispaly on.
  • The command 0x0c dispaly on cursor off(displays cursor off but the text will appear on lcd)
  • The command 0x0F dispaly on cursor blink(text will appear on screen and cursor will blink).
  • The command 0x18 shift entire dispaly left(shift whole off the text on the particular line to its left ).
  • The command 0x1C shift entire dispaly right(shift whole off the text on the particular line to its right).
  • The command 0x10 Moves cursor one step left or move cursor on step a head to left when ever new character is displayed  on the screen.
  • The command 0x14  Moves cursor one step right or move cursor on step a head to righ when ever new character is displayed on the screen. 
  • The command 0x01 clear all the contents of the DDRAM and also clear the lcd removes all the text from the screen.
  • The command 0x80 initialize the cursor to the first position means first line first matrix(start point) now if we add 1 in 0x80+1=0x81 the cursor moves to second matrix.

NOTE: You can send commands in hexadecimal or decimal form which one do you like the result is same because the microcontroller translate the command in 8-bit binary value and sends it to the lcd.

Difference between 4-bit and 8-bit Lcd Mode

Character Lcd’s can be used in 4-bit and 8-bit mode. Before you send commands and data to your lcd. Lcd must first be initialized. This initialization is very important for lcd that are made by Hitachi because they use HD44780 driver chip sets. Hd44780 Chip set  first has to be initialized before using it. If you don’t initialize it properly you will see nothing on your lcd.

For 8-bit mode, this is done as follows:

1. Wait more than 15 mill secs after power is applied.
2. Write command 0x30 to LCD and wait 5 milli seconds for the instruction to complete.
3. Write command 0x30 to LCD and wait 160 micro seconds for instruction to complete.
4. Write command 0x30 AGAIN to LCD and wait 160 micro seconds or Poll the Busy Flag.

In 4-bit mode the high nibble is sent first before the low nibble and the En pin is toggled each time four bits is sent to the LCD. To initialize in 4-bit mode:

1. Wait more than 15 mill secs after power is applied.
2. Write command 0x03 to LCD and wait 5 msecs for the instruction to complete.
3. Write command 0x03 to LCD and wait 160 usecs for instruction to complete.
4. Write command 0x03 AGAIN to LCD and wait 160 usecs (or poll the Busy Flag).
Write 0x02 to the LCD to Enable 4-Bit Mode

To learn more about the difference between 4-bit and 8-bit character lcd mode and operation with demo example visit the tutorial link given below. Demo examples are very easy to understand and one can make changes easily in the code. Please also give us your feed back on the post.

 Part 0: https://www.engineersgarage.com/16x2-lcd-working/

Thứ Hai, 8 tháng 8, 2022

Making and displaying Custom characters on lcd with Arduino Uno and 16×2 lcd (LCD: Part 2)

 

This project is about displaying custom characters on 16×2 character lcd using arduino uno microcontroller. With ardunio uno its very easy to display custom characters on lcd. In arduino their is built in structure to generate custom character like many other features which make it perfect board for embedded system projects or diy(do it yourself) projects etc. 

What are custom characters?

Custom characters are self made characters which we design by our self. We have full control on designing them with some constraints which i will discuss later. Like if we want to display a smiley 🙂 on 16×2 lcd. We don’t have an ASCII character for smiley to display it on 16×2 lcd. Example of custom characters is below

Example of custom characters displayed on 16x2 lcd 

Example of custom characters displayed on 16×2 lcd

How custom characters are made and displayed on 16×2 lcd?

Before beginning any further i recommend you to please take the 16×2 lcd display introduction tutorial. Taking the tutorial will let you know about the pin out and internal structure of 16×2 lcd

16×2 lcd has an internal ​CG-RAM(character generated ram) in which we can generate or place our custom character. CG-RAM size is 64 bytes. We can generate/place 8 characters of size 5×8 at a time in CG-RAM. We can also place 5×10 size characters in CG-RAM but only 4.

5×8 represents the dimension of the matrix in which a particular character can be displayed. 5 represents the number of coulombs and 8 represents the number of rows. 5×8 combined is a matrix size. Matrix is composed of pixels which we turn on and off to represent or make a character. For example to display a smiley 🙂 in 5×8 dimension individual pixels on and off will be same like below.

5x8 pixel dimension of custom character display 

5×8 pixel dimension of custom character display

For each 5×8 matrix with custom character in it we have to translate it in to its equivalent bits. For example the binary value of rows in 5×8 matrix is shown below. Against each binary value its HEX code is also given.

  • Each switched on pixel binary value is ‘1‘.
  • Each switched off pixel binary value is ‘0‘.

  16×2 custom character smiley binary bits

 The above binary or hex values are then arranged in a byte array. Byte array is then placed in to CG-RAM of 16×2 lcd. Now when we want to display this smiley character on lcd screen we just call its address in CG-RAM and finally the character will appear on 16×2 lcd screen.

I almost explained every thing above, about generating custom characters in 16×2 lcd CG-RAM and displaying them on lcd screen. But still their are few things which are not part of this tutorial. Like custom character address in CG-RAM. Its because the arduino ide has pre-defined library which places the custom characters in CG-RAM and call it when needed for display. If you want to know about whats happening behind the library then  i recommend you to please learn about the custom character generation in internal hardware level first before proceeding.

Arduino custom characters displayed on 16×2 lcd – Circuit diagram

For this project you only need a 16×2 character lcd and arduino uno microcontroller/board. You can use any other character lcd according to your wish but remember to change the lcd.begin(no of coulombs of lcd, no of rows of lcd) command in code and insert the dimensions of the lcd you are interfacing with arduino uno. Almost all the character lcd’s have same pin out and uses same hd44780 lcd controller. So their will be no difference in circuit diagram or remaining code. Hd44780 lcd controller is responsible to display characters on character lcd, communicate with external devices and CG-RAM also resides in HD44780 lcd controller.  

In this project i am using 16×2 lcd in 4-bit mode so you have to make pin connections according to the 4-bit mode. Its not very hard just connect in the order given below.

  • LCD RS pin to digital pin 13 of arduino uno
  • LCD Enable pin to digital pin 12 of arduino uno
  • LCD D4 pin to digital pin 11 of arduino uno
  • LCD D5 pin to digital pin 10 of arduino uno
  • LCD D6 pin to digital pin 9 of arduino uno
  • LCD D7 pin to digital pin 8   of arduino uno

 Custom characters displayed on 16x2 lcd using arduino uno

 

Arduino custom character display – Project code

The code of the project is simple. I am going to display 8 custom character on 16×2 lcd. First the required characters byte array are declared in code. Byte arrays are declared in binary as well as hexadecimal format.

The createChar() command in ardunio ide is very important. It creates/puts the character matrix/array against an addres in CG-RAM of 16×2 lcd. In other microcontrollers we have to write the memory address where we want to place our newly created custom character but in ardunio the createChar() command creates the required character automatically and place it against an address in CG-RAM. createChar() function is part of LiquidCrystal library. If we open the library and see the function statements they are communicating with the HD44780 lcd controller and CG-RAM address are defined in the function.

Arduino code steps to create and display custom characters on 16×2 lcd

byte a[8]={B00000,B01010,B00100,B00100,B00000,B01110,B10001,};
The above statement is a byte array of a custom character in binary format.
lcd.createChar(2 , a);
The above command places the a[] byte array custom character against address 2 in CG-RAM. Real address is different its not 2 see library for real address.
lcd.write(2);
The above command displays the custom character placed against the address 2 in CG-RAM.


#include<LiquidCrystal.h>     

LiquidCrystal lcd(13 ,12, 11, 10, 9, 8); //16x2 lcd arduino interface pins
 
//Custom characters byte arrays
byte customchar[8]={B00000,B01010,B00000,B00000,B00000,B00000,B11111,};
byte a[8]={B00000,B01010,B00100,B00100,B00000,B01110,B10001,};
byte s[8]={B00100,B01010,B10001,B10001,B01010,B00100,};
byte s1[8]={B01110,B01010,B11111,B11011,B11111,B01010,B01110,};
byte s2[8]={B01010,B00100,B00100,B01010,B10001,B00100,B10001,};
byte s3[8]={B00100,B01010,B11111,B01010,B10101,B11011,B10001,};
byte s4[8]={0x1F,0x11,0x11,0x11,0x11,0x11,0x1F,};
byte s5[8]={B11111,B11101,B11011,B11101,B11111,B10000,B10000,B10000,};
//Custom characters byte arrays

void setup()
{
lcd.begin(16 ,2); //Initialize 16x2 lcd
lcd.clear(); //Clear lcd display screen

lcd.createChar(1 , customchar); //Creating custom characters in CG-RAM
lcd.createChar(2 , a);
lcd.createChar(3 , s);
lcd.createChar(4 , s1);
lcd.createChar(5 , s2);
lcd.createChar(6 , s3);
lcd.createChar(7 , s4);
lcd.createChar(8 , s5); //Creating custom characters in CG-RAM
}
void loop()
{
int rand,i;
lcd.setCursor(0 ,0); //Place lcd cursor on first row and first coulomb of 16x2 lcd
lcd.print("Cust Character!!"); //Display this test on first row on 16x2 lcd
lcd.setCursor(0 ,1); //Place lcd cursor on second row of 16x2 lcd first coulomb

for(rand=0;rand<10;rand++){ //For loop will display custom characters one by one
i=random(10);
lcd.setCursor(i ,1);
lcd.write(i); //-->>>PRINTING/DISPLAYING CUSTOM CHARACTERS
delay(500);
}
lcd.clear(); //Clear lcd and start again
}

Numerous custom character generators are available online i usually use maxpromer its easy to use and biggest advantage of it is. It can generate whole arduino code in just seconds. Just give it a try i bet you gone love it.

maxpromer custom character generator online 

More projects regarding custom characters, arduino and other microcontroller. All the projects are open source. Each and every statement with circuit diagram of the projects are well explained in the tutorials. 

Part 2: https://www.engineersgarage.com/making-custom-characters-on-lcd-using-arduino/