Electronics

How to fix Raspberry Pi GPIO “No access to /dev/mem. Try running as root!”

Problem:

You want to toggle a Raspberry Pi GPIO pin using RPi.GPIO but you see an error message like

Traceback (most recent call last):
  File "gpio.py", line 8, in <module>
    GPIO.setup(pin1, GPIO.OUT)
RuntimeError: No access to /dev/mem.  Try running as root!

Solution:

Add your user to the gpio group:

sudo usermod -a -G gpio $USER

then log out and log back in (or reboot, if that doesn’t help).

The reason for this error is that /dev/gpiomem is only accessible by users belonging to the gpio group. By default, only the pi user belongs to the gpio group – hence, if you run a script as any users other than pi or root, you will see that error message.

Posted by Uli Köhler in Electronics, Raspberry Pi

What is the relay lifetime of a REX C100 PID controller?

The popular yet inexpensive REX C100 PID temperature controller typically contains a mechanical relay.

Mechanical relays will fail after some number of switching cycles. There are two types of relay lifetime specification relevant for these applications:

  • Electrical lifetime: How many switching cycles until the electrical characteristics degrade beyond the specification. Typically the relay will have increased on-state resistance when old.
  • Mechanical lifetime: How many cycles until the relay can’t switch properly any more due to  mechanical wear. Typically, after reaching its mechanical life, the relay will stick either open or closed.

My REX C100 (model 10G8888) contain Hongfa HF3FD/012-ZTF relays.
According to their datasheet, these relays have an electrical life of 50 000 cycles and a mechanical life of 10 000 000 cycles.

This means that if the REX C100 switches on and off every 12 seconds (like most standard Rex C100):

  • The electrical lifetime of the relay will be reached after 600 000 seconds, i.e. 1.74 days of continous operation.
  • The mechanical lifetime of the relay will be reached after 120 000 000 seconds, i.e. 3.8 years of continous operation.
Relay lifetime online calculator
TechOverflow calculators: Free, interactive, easy to use

Often the best strategy is to design your circuit so you don’t depend on the electrical characteristics of the relay entirely, but your application will continue to work even with degraded contact resistance.

My recommendation is to design your application to tolerate 3-5 times the contact resistance and use only 1/3 of the rated current.

Note that the manufacturer’s specification should be considered to be just an estimation of your relay’s lifetime. The actual lifetime will vary between individual relays. If used properly, most if not all individual relays will reach their specified lifetime.

Note: Some REX 100 models have solid state relays. If you hear an audible clicking noise every time the REX C100 switches on your load, it’s a mechanical relay. The SSR-model REX 100 do not have an internal relay but need to be connected to an external SSR. These models switch much faster, approximately once every 3 seconds.

Posted by Uli Köhler in Electronics

Incandescent bulb power calculator

TechOverflow calculators:
You can enter values with SI suffixes like 12.2m (equivalent to 0.012) or 14k (14000) or 32u (0.000032) as well as values with units (like 12V).
The results are calculated while you type and shown directly below the calculator, so there is no need to press return or click on a Calculate button. Just make sure that all inputs are green by entering valid values.

V

A

P_{\text{bulb}} = U_{\text{bulb}} \cdot I_{\text{bulb}}
Posted by Uli Köhler in Calculators, Electronics

Relay coil current calculator (from coil power and voltage)

TechOverflow calculators:
You can enter values with SI suffixes like 12.2m (equivalent to 0.012) or 14k (14000) or 32u (0.000032) as well as values with units (like 12V).
The results are calculated while you type and shown directly below the calculator, so there is no need to press return or click on a Calculate button. Just make sure that all inputs are green by entering valid values.

V

W

I_{\text{coil}} = \frac{P_{\text{coil}}}{U_{\text{coil}}}
Posted by Uli Köhler in Calculators, Electronics

mbed STM32F4DISCOVERY simple LED demo

This demo shows you how to control the STM32F4DISCOVERY LEDs using mbed.
I use mbed from inside PlatformIO.

#include <mbed.h>

DigitalOut greenLED(PD_12);
DigitalOut orangeLED(PD_13);
DigitalOut redLED(PD_14);
DigitalOut blueLED(PD_15);

int main() {
  while(1) {
    // Cycle LEDs in order
    // NOTE: You can toggle a LED using
    //  blueLED = !blueLED;
    blueLED = 0;
    greenLED = 1;
    wait(0.25);
    greenLED = 0;
    orangeLED = 1;
    wait(0.25);
    orangeLED = 0;
    redLED = 1;
    wait(0.25);
    redLED = 0;
    blueLED = 1;
    wait(0.25);
  }
}

 

Posted by Uli Köhler in mbed, PlatformIO

STM32F4DISCOVERY LED pin reference / pinout

The STM32F4 DISCOVERY board has these LEDs:

  • Green LED: PD12, active-high (LED emits light when PD12 is high)
  • Orange LED: PD13, active-high (LED emits light when PD13 is high)
  • Red LED: PD14, active-high (LED emits light when PD14 is high)
  • Blue LED: PD15, active-high (LED emits light when PD15 is high)
Posted by Uli Köhler in Electronics, Embedded

Is pypng 16-bit PNG encoding faster using pypy on the Raspberry Pi?

In our previous post How to save Raspberry Pi raw 10-bit image as 16-bit PNG using pypng we investigated how to use the pypng library to save 10-bit raw Raspberry Pi Camera images to 16-bit PNG files.

However, saving a single image took ~26 seconds using CPython 3.7.3. Since pypy can provide speedups to many Python workloads, we tried using pypy3 7.0.0 (see How to install pypy3 on the Raspberry Pi) to speed up the PNG encoding.

Results

pypng PNG export seems to be one of the workloads that are much slower using pypy3.

  • CPython 3.7.3: Encoding took 24.22 seconds
  • pypy3 7.0.0: Encoding took 266.60 seconds

Encoding is more that 10x slower when using pypy3!

Hence I don’t recommend using pypy3 to speed up pypng encoding workloads, at least not on the Raspberry Pi!

Full example

This example is derived from our full example previously posted on How to save Raspberry Pi raw 10-bit image as 16-bit PNG using pypng:

#!/usr/bin/env python3
import time
import picamera
import picamera.array
import numpy as np
import png

# Capture image
print("Capturing image...")
with picamera.PiCamera() as camera:
    with picamera.array.PiBayerArray(camera) as stream:
        camera.capture(stream, 'jpeg', bayer=True)
        # Demosaic data and write to rawimg
        # (stream.array contains the non-demosaiced data)
        rawimg = stream.demosaic()

# Write to PNG
print("Writing 16-bit PNG...")
t0 = time.time()
with open('16bit.png', 'wb') as outfile:
    writer = png.Writer(width=rawimg.shape[1], height=rawimg.shape[0], bitdepth=16, greyscale=False)
    # rawimg is a (w, h, 3) RGB uint16 array
    # but PyPNG needs a (w, h*3) array
    png_data = np.reshape(rawimg, (-1, rawimg.shape[1]*3))
    # Scale 10 bit data to 16 bit values (else it will appear black)
    # NOTE: Depending on your photo and the settings,
    #  it might still appear quite dark!
    png_data *= int(2**6)
    writer.write(outfile, png_data)
t1 = time.time()

print(f"Encoding took {(t1 - t0):.2f} seconds")

 

Posted by Uli Köhler in Python, Raspberry Pi

How to install pypy3 on the Raspberry Pi

This post shows you an easy way of getting pypy3 running on the Raspberry Pi. I used Raspbian Buster on a Raspberry Pi 3 for this example. On Raspbian buster this will install pypy3 7.x!

First install pypy3 and virtualenv:

sudo apt update && sudo apt -y install pypy3 pypy3-dev virtualenv

Now we can create a virtualenv to install pypy packages into:

virtualenv -p /usr/bin/pypy3 ~/pypy3-virtualenv

Now we can activate the virtualenv. You need to do this every time you want to use pypy, for each shell / SSH connection separately:

source ~/pypy3-virtualenv/bin/activate

If your shell prompt is now prefixed by (pypy3-virtualenv) you have successfully activated the virtualenv:

(pypy3-virtualenv) uli@raspberrypi:~ $

Now python points to pypy3 and pip will install packages locally to ~/pypy3-virtualenv.

Now you can use e.g.

python3 myscript.py

to run your script (both python and python3 will point to pypy3 if you activated the virtual environment!).

Note: Installing pypy3-dev is not strictly neccessary to get pypy3 running, but you need it in order to compile native librarie like numpy.

Posted by Uli Köhler in Python, Raspberry Pi

How to save Raspberry Pi raw 10-bit image as 16-bit PNG using pypng

In our previous post How to capture RaspberryPi camera 10-bit raw image in Python we showed how you can use the picamera Python library to capture raw 10-bit image data.

The PNG image format supports storing 16-bit image data. This post shows you how to do that using the NumPy arrays we generated in our previous post. We are using the pypng library.

with open('16bit.png', 'wb') as outfile:
    writer = png.Writer(width=rawimg.shape[1], height=rawimg.shape[0], bitdepth=16, greyscale=False)
    # rawimg is a (w, h, 3) RGB uint16 array
    # but PyPNG needs a (w, h*3) array
    png_data = np.reshape(rawimg, (-1, rawimg.shape[1]*3))
    # Scale 10 bit data to 16 bit values (else it will appear black)
    # NOTE: Depending on your photo and the settings,
    #  it might still appear quite dark!
    png_data *= int(2**6)
    writer.write(outfile, png_data)

Note that the resulting PNGs are ~9.9 Megabytes in size and saving them using pypng takes about 27 seconds to save the image on my Raspberry Pi 3!

For comparison, the raw NumPy data is ~29 Megabytes whereas the compressed NumPy data is 9.3 Megabytes,

  • Raw NumPy data (np.save): 29 Megabytes, takes 0.11 seconds to save.
  • Compressed NumPy data (np.savez_compressed): 9.3 Megabytes, take 12 seconds to save.

So if your motivation for using PNG is to save space, you might be better off using NumPy compressed data, especially if you need to save many camera frames in quick succession and hence are limited.

In case you need to use PNGs, you might want to check Pypy since pypng is a pure Python library and hence might benefit from Pypy’s increased execution speed. However, in practice, pypy3 is more than 10x slower. Please read our detailed analysis at Is pypng 16-bit PNG encoding faster using pypy on the Raspberry Pi?

Full example:

#!/usr/bin/env python3
import picamera
import picamera.array
import numpy as np
import png

# Capture image
print("Capturing image...")
with picamera.PiCamera() as camera:
    with picamera.array.PiBayerArray(camera) as stream:
        camera.capture(stream, 'jpeg', bayer=True)
        # Demosaic data and write to rawimg
        # (stream.array contains the non-demosaiced data)
        rawimg = stream.demosaic()

# Write to PNG
print("Writing 16-bit PNG...")
with open('16bit.png', 'wb') as outfile:
    writer = png.Writer(width=rawimg.shape[1], height=rawimg.shape[0], bitdepth=16, greyscale=False)
    # rawimg is a (w, h, 3) RGB uint16 array
    # but PyPNG needs a (w, h*3) array
    png_data = np.reshape(rawimg, (-1, rawimg.shape[1]*3))
    # Scale 10 bit data to 16 bit values (else it will appear black)
    # NOTE: Depending on your photo and the settings,
    #  it might still appear quite dark!
    png_data *= int(2**6)
    writer.write(outfile, png_data)

 

Posted by Uli Köhler in Raspberry Pi

How to capture RaspberryPi camera 10-bit raw image in Python

You can use the picamera Python library to capture a raw sensor image of a camera attached to the Raspberry Pi via CSI:

#!/usr/bin/env python3
import picamera
import picamera.array
import numpy as np

# Capture image
print("Capturing image...")
with picamera.PiCamera() as camera:
    with picamera.array.PiBayerArray(camera) as stream:
        camera.capture(stream, 'jpeg', bayer=True)
        # Demosaic data and write to rawimg
        # (stream.array contains the non-demosaiced data)
        rawimg = stream.demosaic()

rawimg is a numpy uint16 array of dimensions (w, h, 3), e.g. (1944, 2592, 3) and contains integer values from 0 to 1023.

You can, for example, save it in a NumPy file using

np.save("rawimg.npy", rawimg) # Reload with np.load("rawimg.npy")

or save it in a compressed format using

np.savez_compressed("rawimg.npz", rawimg) # Reload with np.load("rawimg.npz")
Posted by Uli Köhler in Python, Raspberry Pi

How to fix ModuleNotFoundError: No module named ‘picamera’

Problem:

You want to run a Python script using the Raspberry Pi camera but you see an error message like

Traceback (most recent call last):
  File "mycamera.py", line 2, in <module>
    import picamera
ModuleNotFoundError: No module named 'picamera'

Solution:

You need to install the picamera Python module using pip:

sudo pip3 install picamera

or, if you are still using Python 2.x:

sudo pip install picamera

In case you see

sudo: pip3: command not found

install pip3 using

sudo apt install -y python3-pip

 

Posted by Uli Köhler in Python, Raspberry Pi

Reading and writing KiCAD libraries in Python

This snippet provides a parser and serializer for KiCAD schematic symbol libraries and DCM symbol documentation libraries. It will parse the KiCAD libraries into a number of records, consisting of a list of lines. An extended version of this snippet has been used in my KiCADSamacSysImporter project

__author__ = "Uli Köhler"
__license__ = "CC0 1.0 Universal"

class KiCADDocLibrary(object):
    def __init__(self, records=[]):
        self.records = records
        
    @staticmethod
    def read(file):
        # A record is everything between '$CMP ...' line and '$ENDCMP' line
        records = []
        current_record = None
        for line in file:
            line = line.strip()
            if line.startswith('$CMP '):
                current_record = []
            # Add line to record if we have any current record
            if current_record is not None:
                current_record.append(line)
            if line.startswith("$ENDCMP"):
                if current_record is not None:
                    records.append(current_record)
                    current_record = None
        return KiCADDocLibrary(records)
        
    def write(self, out):
        # Write header
        out.write("EESchema-DOCLIB  Version 2.0\n")
        # Write records
        for rec in self.records:
            out.write("#\n")
            for line in rec:
                out.write(line)
                out.write("\n")
        # Write footer
        out.write("#\n#End Doc Library\n")        

        
class KiCADSchematicSymbolLibrary(object):
    def __init__(self, records=[]):
        self.records = records
        
    @staticmethod
    def read(file):
        # A record is everything between 'DEF ...' line and 'ENDDEF' line
        records = []
        current_record = None
        current_comment_lines = [] # 
        for line in file:
            line = line.strip()
            if line.startswith("#encoding"):
                continue # Ignore - we always use #encoding utf-8
            # Comment line processing
            if line.startswith("#"):
                current_comment_lines.append(line)
            # Start of record
            if line.startswith('DEF '):
                current_record = current_comment_lines
                current_comment_lines = []
            # Add line to record if we have any current record
            if current_record is not None:
                current_record.append(line)
            if line.startswith("ENDDEF"):
                if current_record is not None:
                    records.append(current_record)
                    current_record = None
            # Clear comment lines
            # We can only do this now to avoid clearing them before
            #  they are used in the DEF clause
            if not line.startswith("#"):
                current_comment_lines = []
        return KiCADSchematicSymbolLibrary(records)
        
    def write(self, out):
        # Write header
        out.write("EESchema-LIBRARY Version 2.4\n#encoding utf-8\n")
        # Write records
        for rec in self.records:
            for line in rec:
                out.write(line)
                out.write("\n")
        # Write footer
        out.write("#\n#End Library\n")        

 

Posted by Uli Köhler in Electronics, KiCAD, Python

How to initialize your KiCAD project on the command line

Note: This script initializes a KiCAD project in the recommended configuration (i.e. with project-specific footprint and symbol libraries). In case you want to initialize an empty project, see How to initialize an empty KiCAD project on the command line

TL;DR:

Inside the directory where you want to create the project, run

wget -qO- https://techoverflow.net/scripts/kicad-init.sh | bash /dev/stdin MyProject

You should replace MyProject (at the end of the command) with your project name.

Note: This will initialize an empty KiCAD project without any libraries. This is equivalent to creating a new project in KiCAD itself (using the GUI).

Continue reading →

Posted by Uli Köhler in Electronics, KiCAD, Shell

How to initialize an empty KiCAD project on the command line

TL;DR:

Note: We recommend to use our new script to initialize a project with project-specific footprint and symbol libraries, see How to initialize your KiCAD project on the command line. The script on this page initializes an empty project without any libraries.

Inside the directory where you want to create the project, run

wget -qO- https://techoverflow.net/scripts/kicad-initialize.sh | bash /dev/stdin MyProject

You should replace MyProject (at the end of the command) with your project name.

Note: This will initialize an empty KiCAD project without any libraries. This is equivalent to creating a new project in KiCAD itself (using the GUI).

Continue reading →

Posted by Uli Köhler in Electronics, KiCAD, Shell

Should you use I2C or SPI devices for your project?

It depends on what you want to achieve. 

Note that some devices are only available as either I2C or SPI device and quite often the best solution is to use both I2C and SPI if you have enough pins to spare on your microcontroller. Many designers assume the bus is the primary selection criterion for part search, but often a part’s performance and price are more important than the interface it uses!

Advantages of I2C:

  • I2C uses only two pins (as opposed to SPIs three pins plus one address pin for each device for most configurations)
  • I2C can support multiple devices with the same two pins if each of them has a different address.
  • The I2C standard defines how to read and write to/from a specific address, hence you don’t need to check the datasheet as thoroughly for every individual device. Note that many complex devices extend this standard to a certain extent, e.g. larger EEPROMs have multiple I2C addresses to allow accessing the entire memory.
  • I2C has fewer parameters to configure since the speeds and other attributes are fixed in the standard (100 kbit/s, 400 kbit/s or 1 MBit/s = FM+). Hence you don’t need to worry about SPI modes or configuring the SPI speed correctly for any device.
  • The by-default slower speed of I2C makes it more likely for I2C to work over longer traces / wires out-of-the box. SPI is more prone to experiencing intermittent issues if operating at or near the phyiscal speed limit of a PCB design. With I2C it’s typically safe to assume it will work over 50cm long traces (for the standard 400 kbit/s speed). The only reason for I2C working over longer traces than SPI is it’s slower specified speed. SPI will work just as well if you set the speed sufficiently low.

Advantages of SPI:

  • SPI is much faster. While I2C typically communicates at 400 kbit/s (in Fast mode plus = FM+: 1 Mbit/s), SPI communicates around 20-50 MBit/s (it varies depending on your configuration and what speed each part supports). However for many applications you don’t need as much speed.
  • With SPI you don’t need to worry about assigning I2C addresses since each device has its own chip select pin. See our guide on assigning I2C addresses for more details.
  • SPI is more flexible in what data can be transferred since the communication message format is not standardized as much as in I2C.
  • Each SPI pin communicates only in a single direction. Hence SPI is much easier to galvanically isolate using optocouplers or similar devices. I2C requires special (and hence expensive) isolator devices like the TI ISO1541.
  • SPI is typically slighly easier to debug using an oscilloscope since you know what device the data comes from for every individual pin. With I2C, you need to have a look at the data sent to find out what device tries to send data.
  • I2C sometimes experiences issues due to locked-up devices if an I2C communication is interrupted mid-byte (e.g. by a microcontroller restart) and hence causes a device’s state machine to remain in a state mismatched to the I2C master’s state. Most designers do not anticipate this issue and do not include I2C lockup mitigation in their firmware. This means that often a complete power cycle of a system is required in order to remove the bus lockup. The issue occurs more often during firmware development when microcontroller reboots are more frequent due to reprogramming, crashes and breakpoints and in production tests it’s often hard to create the specific conditions that create a lockup in deployment. SPI can never lock up because it will reset once the chip select pin is deasserted.
  • SPI can often be used to control logic ICs like th 74HC series so you don’t need separate pins to control logic devices. Note that whether this works

In what cases do you need to use a different interface (other than I2C or SPI)?

  • Long cables / lines. SPI and I2C operate reliably up to a few tens of centimeters depending on your layout and the speed of the bus. In case you have longer traces, you might need to slow down the bus (especially in the case of SPI). The main issue here is clock skew: A change of the voltage level on the clock pin takes too long to arrive at the device, hence the device “answers too late” (additionally the response from the device takes too long to arrive at the master). If you want to check if this is the case for your design, just slow down your bus to extremely slow speeds (like 20 kbit/s). If the issue persists, you don’t have an issue with clock skew. You can also debug that using an oscilloscope.
  • Electromagnetic noise from the environment, e.g. large motors starting in the vincinity of your device. Since both I2C do not use differential lines
  • Multi-master communication: I2C and SPI typically only communicate when a (pre-defined) master initiates the communication. In most configurations, it’s not possible for a device to initiate communication using only the I2C or SPI bus, so you often need to poll a device many times per second to check if a status has changed. I2C and SPI do not have a built-in collision detection mechanism that detects if multiple devices are trying to write to the bus at the same time.
  • Asynchronous communications: If you want to send/receive data independently from each other, you should use UART, Ethernet or a similar bus that has completely independent send/receive subsystems that do not depend on a common clock.
  • Very fast communication: FPGAs, fast ADCs/DACs, flash memories etc might use e.g.:
    • QSPI: SPI with multiple data pins (typically 4 data pins – hence the name quad SPI).
    • LVDS: High-speed differential bus system
    • JESD204B: Ultra-high speed (multi-gigabit) data link system for ICs. Don’t touch if you don’t know what you’re doing!
    • Parallel: Just a lot of pins without anything too special.

What other interfaces should you consider if communicating outside the circuit board?

  • RS485/RS422: Robust high-speed industrial bus (physical layer only, used in systems like Profibus). Fast (15 MBit/s). RS422 is like UART but differential. RS485 operates receive/transmit on the same differential line.
  • RS232: Old industrial bus system, not differential, requires +-15V to communicate (and hence requires a special IC to generate these voltage levels). Somewhat robust, but not as robust as it seems. Slow (0.1 MBit/s typical, but typically works up to ~0.5 Mbit/s under most circumstances, if all devices support it), does not support long cables, especially not in electromagnetically noisy environments.
  • LVDS: High speed, but not over long distances (a few meters at most). Differential and somewhat robust, but not that suitable for noisy industrial environments if used with long-ish cables. Requires knowledge of high-speed circuit design to do correctly.
  • Ethernet: Very complex to do right from a PCB standpoint (you need a special PHY = physial layer transceiver IC and a microcontroller that supports the MAC layer that generates the Ethernet messages = frames) but very fast (100 Mbit/s max for most microcontrollers, but FPGAs, processors etc) and very robust (differential, 32-bit CRC checksums). Very convenient to interface to computers ; switchable. Supports TCP/IP. PHYs and other hardware are very cheap since they are produced in large quantities. Note: PHYs are rather complex and if you don’t understand some basics of high-speed circuit design and read all the datasheets very carefully, you have a high likelyhood of your design not working – which is often complex to debug especially if you don’t have a multichannel Oscilloscope capable of at least 50 MHz of Bandwidth and some experience in high speed circuit debugging. The interface from the PHY to your microcontroller ist typically RMII for 100 MBit/s Ethernet, additionally you need and SMC interface which is like I2C in order to configure the PHY.
  • USB: Fast, but only goes up to 480 MBit/s under ideal circumstances if your IC actually supports it (many need an external transceiver = USB HS PHY). Most microcontrollers support only up to 12 MBit/s IC . Complex, unless you use ready-to-use ICs. Debugging is pretty hard in practice since USB firmware can fail in many non-straightforward ways (unless, again, for ready-to-use ICs that only perform USB-to-X-conversion). I recommend to use an USB-to-UART-converter IC like the FT230XQ. USB on microcontrollers sometimes tends not to work with some computers unless done completely right, so if possible to try to use a professionally-made USB example that has been tested with a variety of devices and try to not modify it too much. Or just use a ready-to-use converter IC in the first place.
  • UART: Useful for debugging but not robust. UART-to-USB ICs are widely available (I currently recommend the FT230XQ) to interface to computers. Somewhat fast (can do up to ~12 MBit/s with many modern microcontrollers, but it’s not always feasible to use it at that speed, especially not with long traces / cables due to signal degradation). USB-to-UART adapters for debugging are readily available & very cheap in China.
  • CAN: Used mostly in automotive systems. Not very fast (1 MBit/s) but has a priority system that allows high-priority message to be sent during transmission of lower-priority messages (which are interrupted and re-sent later). Differential and quite robust. Mostly easy to use on the IC level but hard to do completely right on the firmware level (there are a lot of non-straightforward configuration options).
Posted by Uli Köhler in Electronics

How many bits does an I2C address have?

I2C addresses always have 7 bits.

This is because the first byte in any I2C communication consists of the 7 bit address plus the Read/Write bit. The Read/Write bit is 0 if the I2C master requests to write to a specific address and it’s 1 if the I2C master requests to read from an address.

The first byte of the I2C communication looks like this:

Interested in how we made this diagram? Check out our post on How to visualize I2C first byte structure in TikZ

Posted by Uli Köhler in Electronics

How to wire I2C address pins (A0, A1, A2, …)?

When you want to use an I2C device like an EEPROM you might ask yourself how to wire the address pins (A0, A1 and A2).

The prime rule: No unconnected address pins

You need to remember the prime rule of I2C addressing: Never leave address pins unconnected unless explicitly allowed in the datasheet!

While there are some devices like the MCP3472 that allow floating address pins, most devices might not work properly (especially in noisy environments).

The second rule: Avoid address conflicts

You need to avoid having two parts with the same I2C address on the same I2C bus (address collisions)!
The I2C address of an I2C is 7 bits long and typically consists of a part-specific prefix (e.g. 0101) plus address pins (e.g. 0101ABC where A, B and C are the values of the address pins A0, A1 and A2)

First you need to find out whether there are other devices on the same I2C bus, i.e. other ICs that are connected to the same pair of SDA and SCL pins.

  • In case there are no other devices on the same I2C bus, you can wire all the pins to GND (you can also wire any of them to VCC in case that works better for you. If in doubt, wire them to GND!)
  • In case there are other devices on the same I2C bus, you need to proceed as outlined below

How to wire I2C address pins with multiple devices on the same I2C bus?

Multiple ICs with the same part number

If you have multiple ICs with the same part number on the I2C bus (examples: Multiple I2C ADCs, multiple I2C port expanders) it is quite easy to wire them to avoid address collisions: Just wire every one of the ICs differently. This will result in different addresses for each different IC.

Multiple different ICs

As we wrote before, you need to avoid having multiple ICs with the same address.

Most likely, different ICs will have different addresses in the first place, no matter how you wire their pins. However, this is not guaranteed! (if you are feeling lucky, producing only a small batch of prototype boards and don’t mind soldering around, you might as well test your luck and just assume they are different!).

Proceed as follows:

  • Open the datasheets of all the parts you want to use in your design
  • In each datasheet, find the section that lists the address details.

The address details will look like this:

In almost all I2C devices, the first few bits are fixed! The other bits (A_2, A_1 and A_0 in this example) depend on the address pins in one way or another.
While in most devices they represent the address pins directly, some devices try to have more configurable address slots than address pins and hence use floating address pins.

Compare these fixed bits between the devices. In case you can be sure that no two devices can have the same address, you can wire the address pins either to GND or to VCC since it doesn’t matter.

In this example, there obviously can’t be conflicting addresses since some of the fixed bits are different (as indicated by the red lines).

If you can’t be sure that there is no conflict, you need to assign the address pins appropriately so the parts have different I2C addresses.

Our recommendation is to actually write down the I2C addresses and check if they are actually different. This approach avoids hard-to-debug errors. You can do this using old-school pen & paper or do it in any editor.

Note: You should always write down the I2C address of each IC on the schematic, especially if you have multiple I2C parts! Not doing this typically results in having to re-do the calulation over and over again.

Interested on how we made the address diagrams in this post? Check out How to visualize I2C first byte structure in TikZ

Posted by Uli Köhler in Electronics

Voltage divider output voltage calculator (from R1 & R2)

TechOverflow calculators:
You can enter values with SI suffixes like 12.2m (equivalent to 0.012) or 14k (14000) or 32u (0.000032) as well as values with units (like 12V).
The results are calculated while you type and shown directly below the calculator, so there is no need to press return or click on a Calculate button. Just make sure that all inputs are green by entering valid values.

Input voltage:

V

Top resistor:

Ω

Bottom resistor:

Ω

V_{out} = V_{in} \cdot \frac{R_2}{R_1\cdot R_2}
Posted by Uli Köhler in Calculators, Electronics

Does the SAMD21 have pullups on every pin?

Yes, the ATSAMD21 family of microcontrollers has internal pull-ups (and pull-downs) on every Port A / Port B pin (like PB03 or PA14) except PA24 and PA25. You can enable or disable the pullups in software.

The RESET pin also has an internal pull-up which is always active and can’t be disabled.

Posted by Uli Köhler in Electronics