{"id":14940,"date":"2022-06-16T16:12:26","date_gmt":"2022-06-16T16:12:26","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/mcp23x1y-port-expander"},"modified":"2026-03-08T11:51:54","modified_gmt":"2026-03-08T11:51:54","slug":"mcp23x1y-port-expander","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander","title":{"rendered":"MCP23x1y Port Expander"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">About this Post<\/h2>\n\n<p>In one of my first posts, I wrote about the MCP23017 port expander and <a href=\"https:\/\/github.com\/wollewald\/MCP23017_WE\" target=\"_blank\" rel=\"noopener\">my associated library<\/a>. I have since adapted the library so that you can also use it for other members of the MCP23x1y family. That is why I am returning to this topic. In this post, I will primarily discuss the differences between the MCP23x1y ICs. For details that are the same for all members of the MCP23x1y port expander family, please refer to <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/port-expander-mcp23017-2\" target=\"_blank\" rel=\"noopener\">my post about the MCP23017<\/a>.    <\/p>\n<p>Incidentally, the somewhat cumbersome designation MCP23x1y is not official. &#8220;MCP23x&#8221; would also have included the MCP23008 and MCP23S08 models, which I will not discuss in detail here. They only have 8 GPIOs.  <\/p>\n<p>These are the topics I will discuss:<\/p>\n<ul>\n<li><a href=\"#Ueberblick\">Overview of the MCP23x1y family<\/a><\/li>\n<li><a href=\"#Portexpander_im_Detail\">Use of the MCP23x1y port expanders in detail<\/a>\n<ul>\n<li><a href=\"#MCP23017\">MCP23017<\/a><\/li>\n<li><a href=\"#MCP23S17\">MCP23S17<\/a><\/li>\n<li><a href=\"#MCP23018\">MCP23018<\/a><\/li>\n<li><a href=\"#MCP23S18\">MCP23S18<\/a><\/li>\n<li><a href=\"#MCP23016\">MCP23016<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#Geschwindigkeitstests\">I2C vs. SPI \u2013 speed tests<\/a>\n<ul>\n<li><a href=\"#I2C_nano\">I2C using the Arduino Nano<\/a><\/li>\n<li><a href=\"#I2C_esp32\">I2C using the ESP32<\/a><\/li>\n<li><a href=\"#SPI_nano\">SPI using the Arduino Nano<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n<h2 class=\"wp-block-heading\" id=\"Ueberblick\">Overview of the MCP23x1y family<\/h2>\n\n<p>The MCP23x1y family comprises five members:<\/p>\n<ul>\n<li>the MCP23<strong>0<\/strong>1<strong>6<\/strong> (<a href=\"https:\/\/ww1.microchip.com\/downloads\/en\/DeviceDoc\/20090C.pdf\" target=\"_blank\" rel=\"noopener\">link to data sheet<\/a>)<\/li>\n<li>MCP23<strong>0<\/strong>1<strong>7<\/strong> \/ MCP23<strong>S<\/strong>1<strong>7<\/strong> (<a href=\"https:\/\/www.microchip.com\/en-us\/product\/mcp23017\" target=\"_blank\" rel=\"noopener\">link to data sheet<\/a>)<\/li>\n<li>and finally the two MCP23<strong>0<\/strong>1<strong>8<\/strong> \/ MCP23<strong>S<\/strong>1<strong>8<\/strong> (<a href=\"http:\/\/ww1.microchip.com\/downloads\/en\/devicedoc\/22103a.pdf\" target=\"_blank\" rel=\"noopener\">link to data sheet<\/a>)<\/li>\n<\/ul>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-1024x414.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"414\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-1024x414.jpg\" alt=\"MCP23x1y Family\" class=\"wp-image-14317\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-1024x414.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-300x121.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-768x311.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-1536x621.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-2048x829.jpg 2048w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23x1y_family-1320x534.jpg 1320w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">MCP23x1y family (PDIP version)<\/figcaption><\/figure>\n\n<p>Here is an overview of the most important features of the MCP23x1y port expander:<\/p>\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie-1024x474.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"474\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie-1024x474.png\" alt=\"Key differences of the MCP23x1y port expanders at a glance\" class=\"wp-image-14319\" style=\"width:840px;height:388px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie-1024x474.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie-300x139.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie-768x355.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Vergleich_-23x1y_Familie.png 1072w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Key differences of the MCP23x1y port expanders at a glance<\/figcaption><\/figure>\n\n<p>The most common representative is the MCP23017. Like the MCP23018, it is I2C-controlled. If you want to switch or read the GPIOs (General Purpose Input Output) at a higher speed, then use one of the SPI-controlled &#8220;S&#8221; variants.  <\/p>\n<p>The maximum current that can flow through a pin is 25 mA for all members of the MCP23x1y family. However, this current may only flow simultaneously through all pins in the &#8220;18&#8221; variants. These variants also have a restriction regarding the direction of current flow. The GPIOs of the MCP23018 and MCP23S18 are &#8220;open drain&#8221; inputs\/outputs. This means that they behave like a simple transistor. You can open them (set to OUTPUT) and thus &#8220;allow current to flow to ground&#8221;, but you cannot use them as a current source.     <\/p>\n<p>The MCP23016 is special. It is the only one with a different register structure. It also requires an external clock generator. Since it has been labelled &#8220;not recommended for new designs&#8221; by the manufacturer Microchip, I have not bothered to adapt my library for it. However, for the sake of completeness, I have included it in the list.    <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"Portexpander_im_Detail\">Use of the MCP23x1y port expanders in detail<\/h2>\n\n<p>Below, I will discuss the following points for each member of the MCP23x1y family:<\/p>\n<ul>\n<li>Pinout<\/li>\n<li>Connection to the microcontroller<\/li>\n<li>Simple input\/output operations with the<a href=\"https:\/\/github.com\/wollewald\/MCP23017_WE\" target=\"_blank\" rel=\"noopener\"> MCP23017_WE<\/a> library<\/li>\n<\/ul>\n<p>As you can see, I have kept the name of the library. This is because I did not want to confuse those who already use the library. <\/p>\n\n<h3 class=\"wp-block-heading\" id=\"MCP23017\">MCP23017<\/h3>\n\n<h4 class=\"wp-block-heading\">Pinout<\/h4>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout-512x1024.png\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout-512x1024.png\" alt=\"A representative of the MCP23x1y family - Pinout of the MCP23017\" class=\"wp-image-14324\" style=\"width:128px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout-512x1024.png 512w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout-150x300.png 150w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout-768x1536.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_pinout.png 865w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><\/a><\/figure>\n<\/div>\n<p>We&#8217;ll start with the MCP23017. You supply it with 1.8 to 5.5 volts via VDD\/VSS. It is connected to the microcontroller&#8217;s I2C pins via SDA and SCL. The I2C connection often works without pull-up resistors, but I would recommend using them. We do not need the interrupt pins for the sketches used in this article. Connect the reset pin to an I\/O pin on your microcontroller.     <\/p>\n<p>The I2C address is set using the following scheme: 0b00100-A2-A1-A0. If Ax is HIGH, replace it with a 1, otherwise replace it with a zero. So, for example, if you connect A0, A1 and A2 to LOW, the address is 0b00100000 = 0x20 = 32.  <\/p>\n\n<p><strong>Important notice!!!&nbsp;<\/strong> <em>The data sheet for the MCP23017 changed in 2022. According to the new version, pins GPA7 and GPB7 have lost their input function. The pins are now pure OUTPUT pins. Microchip appears to have responded to reported problems with this change. The problems may or may not occur. You can find a statement from Microchip on this <a href=\"https:\/\/microchip.my.site.com\/s\/article\/GPA7---GPB7-Cannot-Be-Used-as-Inputs-In-MCP23017\" target=\"_blank\" rel=\"noopener\">here<\/a>.     Personally, I have not noticed any malfunctions so far. <br><\/em><\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new-1024x341.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"341\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new-1024x341.png\" alt=\"\" class=\"wp-image-17847\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new-1024x341.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new-300x100.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new-768x256.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/06\/pinout_mcp23017_old_new.png 1124w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Pinout MCP23017 old vs. new (from 2022).<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">Example circuit <\/h4>\n\n<p>To try out the sample sketches, connect each GPIO to an LED. When selecting LEDs, keep in mind that the total current at VDD should not exceed 125 milliamps. This means that when all LEDs are lit, each individual LED may only consume an average of approximately 7.8 milliamps. The circuit on an Arduino Nano could look like this:   <\/p>\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-1024x643.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"643\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-1024x643.png\" alt=\"The MCP23017 connected to an Arduino Nano\" class=\"wp-image-14439\" style=\"width:840px;height:527px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-1024x643.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-300x188.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-768x482.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-1536x964.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-542x340.png 542w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano-1320x829.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23017_wiring_ard_nano.png 1539w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The MCP23017 connected to an Arduino Nano<\/figcaption><\/figure>\n\n<p>If, like me, you don&#8217;t feel like wiring sixteen resistors and LEDs, then I recommend LED bars with integrated resistors, as shown below. They are available with a common anode or cathode: <\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-1024x403.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"403\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-1024x403.jpg\" alt=\"LED bars for testing the MCP23x1y port expanders\" class=\"wp-image-14333\" style=\"width:512px;height:202px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-1024x403.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-300x118.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-768x302.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-1536x605.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-2048x806.jpg 2048w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/LED_bar_module-1320x520.jpg 1320w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">LED bars with common cathode (left) or common anode (right)<\/figcaption><\/figure>\n<\/div>\n<p>I found the LED bars on AliExpress, by the way. This makes assembly quick and easy. And they only consume 2 to 3 milliamps per LED. This is what it looked like on my breadboard (without pull-ups):   <\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-1024x527.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"527\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-1024x527.jpg\" alt=\"\" class=\"wp-image-14335\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-1024x527.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-300x155.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-768x396.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-1536x791.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-2048x1055.jpg 2048w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23017_Test-1320x680.jpg 1320w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Example circuit with LED bars connected to the MCP23017<\/figcaption><\/figure>\n<\/div>\n<h4 class=\"wp-block-heading\">Example sketch for the MCP23017<\/h4>\n\n<p>The following example sketch shows how to create your MCP23017 object and control the LEDs with various functions.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"mcp23017_example.ino\" data-enlighter-title=\"mcp23017_example.ino\">#include &lt;Wire.h&gt;\n#include &lt;MCP23017_WE.h&gt;\n#define RESET_PIN 5 \n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n\n\/* There are several ways to create your MCP23017 object:\n * MCP23017_WE myMCP = MCP23017_WE(MCP_ADDRESS)            -&gt; uses Wire \/ no reset pin (if not needed)\n * MCP23017_WE myMCP = MCP23017_WE(MCP_ADDRESS, RESET_PIN)  -&gt; uses Wire \/ RESET_PIN\n * MCP23017_WE myMCP = MCP23017_WE(&amp;wire2, MCP_ADDRESS)    -&gt; uses the TwoWire object wire2 \/ no reset pin\n * MCP23017_WE myMCP = MCP23017_WE(&amp;wire2, MCP_ADDRESS, RESET_PIN) -&gt; all together\n *\/\n \ntypedef MCP23017_WE MCP;\nMCP myMCP = MCP(MCP_ADDRESS, RESET_PIN);  \/\/ short version\n\/\/ MCP23017_WE myMCP = MCP23017_WE(MCP_ADDRESS, RESET_PIN);  \/\/ long version\n\nint wT = 500; \/\/ wT = waiting time\n\nvoid setup(){ \n  Wire.begin();\n  myMCP.Init(); \n  delay(wT);\n  myMCP.setPortMode(0b11111111, MCP::A);  \/\/ Port A: all pins are OUTPUT \n  myMCP.setPortMode(0b11111111, MCP::B);  \/\/ Port B: all pins are OUTPUT\n  myMCP.setAllPins(MCP::A, MCP::ON);      \/\/ Port A: all pins are HIGH\n  myMCP.setAllPins(MCP::B, MCP::ON);      \/\/ Port B: all Pins are HIGH\n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  delay(wT);\n  byte portValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPort(portValue, MCP::A);\n    delay(wT);\n  }\n  portValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPort(portValue, MCP::B);\n    delay(wT);\n  }\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  delay(wT);\n  myMCP.setPin(3, MCP::A, HIGH);          \/\/ Pin 3 \/ PORT A is HIGH\n  myMCP.setPin(1, MCP::B, HIGH);          \/\/ Pin 1 \/ PORT B is HIGH\n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  myMCP.setPortMode(0, MCP::A);           \/\/ Port A: all pins are INPUT \n  myMCP.setPortMode(0, MCP::B);           \/\/ Port B: all pins are INPUT\n  myMCP.setPinX(1, MCP::A, OUTPUT, HIGH); \/\/ A1 HIGH \n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 LOW\n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 HIGH\n  delay(wT); \n  \/\/ the following two lines are similar to setPinX(2,MCP::B,OUTPUT,HIGH);\n  myMCP.setPinMode(2, MCP::B, OUTPUT);    \/\/ B2 is OUTPUT\n  myMCP.setPin(2, MCP::B, HIGH);          \/\/ B2 is HIGH\n  delay(wT); \n  myMCP.setPortX(0b00001111, 0b10001111, MCP::B); \/\/ B0-B4: OUTPUT\/HIGH, B7: INPUT, HIGH;\n}\n\nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>This post is not intended to be a repeat of <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/port-expander-mcp23017-2\" target=\"_blank\" rel=\"noopener\">my first post about the MCP23017<\/a>, but a few explanations are certainly in order so that you don&#8217;t have to jump back and forth between posts.<\/p>\n<p>The GPIOs of the MCP23017 work in principle like those of an Arduino or other microcontrollers. You can set them as INPUT or OUTPUT, and you can switch them to HIGH or LOW. If you supply power to the LEDs via the GPIOs, the pins must be OUTPUT\/HIGH for the LEDs to light up.  <\/p>\n<p>I have added a number of functions to the library that allow you to address individual pins or entire ports. &#8220;0&#8221; is always INPUT or LOW. &#8220;1&#8221; is OUTPUT or HIGH. Instead of HIGH or LOW, you can also use &#8220;ON&#8221; or &#8220;OFF&#8221;. These are all just synonyms for 0 or 1.    <\/p>\n<ul>\n<li><code>setPinMode()<\/code>: determines the mode (INPUT \/ OUTPUT) for a pin.<\/li>\n<li><code>setPortMode()<\/code>: sets INPUT\/OUTPUT for an entire port, but individually for each pin.<\/li>\n<li><code>setPin()<\/code>: sets a pin to HIGH or LOW.<\/li>\n<li><code>setPort()<\/code>HIGH\/LOW for an entire port, but individually for each pin.<\/li>\n<li><code>setAllPins()<\/code>: sets all pins of a port uniformly to HIGH or LOW.<\/li>\n<li><code>setPinX()<\/code>: combines <code>setPinMode()<\/code> and <code>setPin()<\/code> in one function.<\/li>\n<li><code>setPortX()<\/code>: combines <code>setPortMode()<\/code> and <code>setPort()<\/code> in one function.<\/li>\n<li><code>togglePin()<\/code>: switches a pin from HIGH to LOW or vice versa.<\/li>\n<\/ul>\n\n<h3 class=\"wp-block-heading\" id=\"MCP23S17\">MCP23S17<\/h3>\n\n<h4 class=\"wp-block-heading\">Pinout<\/h4>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-510x1024.png\"><img loading=\"lazy\" decoding=\"async\" width=\"510\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-510x1024.png\" alt=\"\" class=\"wp-image-14340\" style=\"width:128px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-510x1024.png 510w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-149x300.png 149w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-768x1541.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout-765x1536.png 765w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S17_pinout.png 865w\" sizes=\"auto, (max-width: 510px) 100vw, 510px\" \/><\/a><\/figure>\n<\/div>\n<p>Unlike the MCP23017, the MCP23S17 is controlled via SPI. Accordingly, it has an SCK (serial clock), SI (slave in), SO (slave out) and a CS (chip select) pin. <\/p>\n<p>At first, it is surprising that it also has the three address pins A0, A1 and A2. When you address the MCP23S17 via SPI, you must first pull the CS pin to LOW as usual. Then you send a control byte consisting of the address and the read\/write bit. This has the advantage that you can connect eight MCP23S17 ICs to one and the same CS line. This is followed by the register byte and then the data. Of course, you don&#8217;t have to worry about these things in detail, as the library takes care of them.     <\/p>\n\n<h4 class=\"wp-block-heading\">Example circuit<\/h4>\n\n<p>The circuit for control via Arduino Nano is not particularly surprising:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-1024x640.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"640\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-1024x640.png\" alt=\"The MCP23S17 connected to an Arduino Nano\" class=\"wp-image-14441\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-1024x640.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-300x187.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-768x480.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-1536x959.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-542x340.png 542w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano-1320x824.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s17_wiring_ard_nano.png 1553w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The MCP23S17 connected to an Arduino Nano<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">Example sketch<\/h4>\n\n<p>Since the MCP23S17 differs from the MCP23017 only in terms of SPI communication, the sample sketch is also only slightly different. One function has been added, namely <code>setSPIClockSpeed()<\/code>. This allows you to select the SPI clock rate within the capabilities of your microcontroller and the MCP23S17 (max. 10 MHz). The default setting for the library is 8 MHz. Otherwise, the sketch requires no further explanation.    <\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"mcp23s17_example.ino\" data-enlighter-title=\"mcp23s17_example.ino\">#include &lt;SPI.h&gt;\n#include &lt;MCP23S17_WE.h&gt;\n#define CS_PIN 7   \/\/ Chip Select Pin\n#define RESET_PIN 5 \n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n\n\/* There are two ways to create your MCP23S17 object:\n * MCP23S17_WE myMCP = MCP23S17_WE(CS_PIN, RESET_PIN, MCP_ADDRESS);\n * MCP23S17_WE myMCP = MCP23S17_WE(&amp;SPI, CS_PIN, RESET_PIN, MCP_ADDRESS);\n * The second option allows you to create your own SPI objects,\n * e.g. in order to use two SPI interfaces on the ESP32.\n *\/\ntypedef MCP23S17_WE MCP; \nMCP myMCP = MCP(CS_PIN, RESET_PIN, MCP_ADDRESS);\n\/\/MCP23S17_WE myMCP = MCP23S17_WE(CS_PIN, RESET_PIN, MCP_ADDRESS);\n\nint wT = 500; \/\/ wT = waiting time\n\nvoid setup(){ \n  SPI.begin();\n  myMCP.Init(); \n  \/\/ myMCP.setSPIClockSpeed(8000000); \/\/ Choose SPI clock speed (after Init()!)\n  delay(wT);\n  myMCP.setPortMode(0b11111111, MCP::A);  \/\/ Port A: all pins are OUTPUT \n  myMCP.setPortMode(0b11111111, MCP::B);  \/\/ Port B: all pins are OUTPUT\n  myMCP.setAllPins(MCP::A, MCP::ON);      \/\/ Port A: all pins are HIGH\n  myMCP.setAllPins(MCP::B, MCP::ON);      \/\/ Port B: all Pins are HIGH\n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  delay(wT);\n  byte portValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPort(portValue, MCP::A);\n    delay(wT);\n  }\n  portValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPort(portValue, MCP::B);\n    delay(wT);\n  }\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  delay(wT);\n  myMCP.setPin(3, MCP::A, HIGH);          \/\/ Pin 3 \/ PORT A is HIGH\n  myMCP.setPin(1, MCP::B, HIGH);          \/\/ Pin 1 \/ PORT B is HIGH\n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all pins are LOW \n  myMCP.setPortMode(0, MCP::A);           \/\/ Port A: all pins are INPUT \n  myMCP.setPortMode(0, MCP::B);           \/\/ Port B: all pins are INPUT\n  myMCP.setPinX(1, MCP::A, OUTPUT, HIGH); \/\/ A1 HIGH \n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 LOW\n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 HIGH\n  delay(wT); \n  \/\/ the following two lines are similar to setPinX(2,B,OUTPUT,HIGH);\n  myMCP.setPinMode(2, MCP::B, OUTPUT);    \/\/ B2 is OUTPUT\n  myMCP.setPin(2, MCP::B, HIGH);          \/\/ B2 is HIGH\n  delay(wT); \n  myMCP.setPortX(0b00001111, 0b10001111, MCP::B); \/\/ B0-B4: OUTPUT\/HIGH, B7: INPUT, HIGH;\n}\n\nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<h3 class=\"wp-block-heading\" id=\"MCP23018\">MCP23018<\/h3>\n\n<p>The MCP23018 is also I2C-controlled. However, there is a fundamental difference to the MCP23017. To light up an LED on the MCP23018, you have to use it as a current sink. This means that you do not supply the LED with current via the MCP23018, but rather allow the current to flow through the MCP23018.    For this to happen, the respective pin must be in the OUTPUT\/LOW state. <\/p>\n\n<h4 class=\"wp-block-heading\">Pinout<\/h4>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-514x1024.png\"><img loading=\"lazy\" decoding=\"async\" width=\"514\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-514x1024.png\" alt=\"\" class=\"wp-image-14347\" style=\"width:129px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-514x1024.png 514w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-151x300.png 151w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-768x1531.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout-771x1536.png 771w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_pinout.png 865w\" sizes=\"auto, (max-width: 514px) 100vw, 514px\" \/><\/a><\/figure>\n<\/div>\n<p>However, the MCP23018 has another special feature. In addition to the different assignment of the GPIOs, it has only a single address pin. The address is set via the voltage applied to the address pin. This is a rather unusual concept, the advantage of which I do not really understand.   <\/p>\n<p>The scale for the &#8220;address voltage&#8221; is determined by the supply voltage VDD. If you apply 1\/16th of the supply voltage to the address pin, the address is 0x20. At 3\/16th, it is 0x21, at 5\/16th it is 0x22, at 7\/16th it is 0x23, etc. You set the highest address 0x27 by applying a voltage of 15\/16th VDD. You can also set 0x20 by going to VSS level (0\/16th) on the address pin and 0x27 by going to VDD level. The tolerances are lower for the other addresses. An overview of the tolerances and sample tables can be found in the <a href=\"http:\/\/ww1.microchip.com\/downloads\/en\/devicedoc\/22103a.pdf\" target=\"_blank\" rel=\"noopener\">data sheet<\/a> on page 11.     <\/p>\n<p>If you want to operate eight MCP23018 ICs, a circuit (reduced to the I2C part) could look like this:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"626\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-1024x626.png\" alt=\"\" class=\"wp-image-14353\" style=\"width:768px;height:470px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-1024x626.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-300x183.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-768x469.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-1536x939.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring-1320x807.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/8_mcp23018_wiring.png 1587w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<h4 class=\"wp-block-heading\">Example circuit<\/h4>\n\n<p>In my example circuit, the LEDs are powered via the Arduino Nano&#8217;s 5 volt output. The current flows through the MCP23018. I set the address using a voltage divider. Since I am only using a single MCP23018 here, I could have alternatively connected the address pin to GND or VDD.   <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-1024x638.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"638\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-1024x638.png\" alt=\"The MCP23018 connected to an Arduino Nano\" class=\"wp-image-14443\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-1024x638.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-300x187.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-768x478.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-1536x957.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano-1320x822.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23018_wiring_ard_nano.png 1554w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The MCP23018 connected to an Arduino Nano<\/figcaption><\/figure>\n\n<p>As before, I made life easy for myself and used LED bars with integrated resistors. In this case, of course, the version with a common anode: <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-1024x378.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"378\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-1024x378.jpg\" alt=\"\" class=\"wp-image-14372\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-1024x378.jpg 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-300x111.jpg 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-768x284.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-1536x567.jpg 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-2048x756.jpg 2048w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/Wiring_MCP23018_Test-1320x487.jpg 1320w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Example circuit with LED bars attached to the MCP23018<\/figcaption><\/figure>\n\n<p>I have also omitted the pull-ups for the I2C lines here (in case you are wondering where they are). However, I added them in the subsequent speed tests. <\/p>\n\n<h4 class=\"wp-block-heading\">Example sketch<\/h4>\n\n<p>At first glance, the sketch does not look very different from the previous ones. But if you take a closer look, you will see that I control the LEDs via OUTPUT\/INPUT and not via HIGH\/LOW. <\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"mcp23018_example.ino\" data-enlighter-title=\"mcp23018_example.ino\">#include &lt;Wire.h&gt;\n#include &lt;MCP23018_WE.h&gt;\n#define RESET_PIN 5 \n#define MCP_ADDRESS 0x20 \n\n\/* There are several ways to create your MCP23018 object:\n * MCP23018_WE myMCP = MCP23018_WE(MCP_ADDRESS)            -&gt; uses Wire \/ no reset pin (if not needed)\n * MCP23018_WE myMCP = MCP23018_WE(MCP_ADDRESS, RESET_PIN)  -&gt; uses Wire \/ RESET_PIN\n * MCP23018_WE myMCP = MCP23018_WE(&amp;wire2, MCP_ADDRESS)    -&gt; uses the TwoWire object wire2 \/ no reset pin\n * MCP23018_WE myMCP = MCP23018_WE(&amp;wire2, MCP_ADDRESS, RESET_PIN) -&gt; all together\n * Successfully tested with two I2C busses on an ESP32\n *\/\ntypedef MCP23018_WE MCP;\nMCP myMCP = MCP(MCP_ADDRESS, RESET_PIN); \/\/ short version\n\/\/ MCP23018_WE myMCP = MCP23018_WE(MCP_ADDRESS, RESET_PIN); \/\/ long version\n\nint wT = 500; \/\/ wT = waiting time\n\nvoid setup(){ \n  Wire.begin();\n  myMCP.Init(); \n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);     \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);     \/\/ Port B: all Pins are LOW\n  myMCP.setPortMode(0b11111111, MCP::A);  \/\/ Port A: all pins are OUTPUT = LEDs are on!\n  myMCP.setPortMode(0b11111111, MCP::B);  \/\/ Port B: all pins are OUTPUT\n  delay(wT);\n  myMCP.setPortMode(0b00000000, MCP::A);  \/\/ Port A: all pins are INPUT = LEDs are off\n  myMCP.setPortMode(0b00000000, MCP::B);  \/\/ Port B: all pins are INPUT\n  delay(wT);\n  byte portModeValue = 0; \/\/ = 0b00000000\n  for(int i=0; i&lt;8; i++){\n    portModeValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPortMode(portModeValue, MCP::A);\n    delay(wT);\n  }\n  portModeValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portModeValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPortMode(portModeValue, MCP::B);\n    delay(wT);\n  }\n  myMCP.setPortMode(0, MCP::A);          \/\/ Port A: all pins are INPUT\n  myMCP.setPortMode(0, MCP::B);          \/\/ Port B: all pins are INPUT \n  delay(wT);\n  myMCP.setPinMode(3, MCP::A, OUTPUT);   \/\/ Pin 3 \/ PORT A is OUTPUT\/LOW\n  myMCP.setPinMode(1, MCP::B, OUTPUT);   \/\/ Pin 1 \/ PORT B is OUTPUT\/LOW\n  delay(wT);\n  myMCP.setPortMode(0, MCP::A);          \/\/ Port A: all pins are INPUT\n  myMCP.setPortMode(0, MCP::B);          \/\/ Port B: all pins are INPUT\n  myMCP.setPinX(1, MCP::A, OUTPUT, LOW); \/\/ A1 HIGH \n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 LOW\n  delay(wT);\n  myMCP.togglePin(1, MCP::A);             \/\/ A1 HIGH\n  delay(wT); \n  \/\/ the following two lines are similar to setPinX(2,B,OUTPUT,LOW);\n  myMCP.setPinMode(2, MCP::B, OUTPUT);    \/\/ B2 is OUTPUT\/LOW\n  myMCP.setPin(2, MCP::B, LOW);           \/\/ B2 is still OUTPUT\/LOW\n  delay(wT); \n  myMCP.setPortX(0b10001111, 0b10000000, MCP::B); \/\/ B0-B4: OUTPUT\/LOW, B7: OUTPUT, HIGH;\n}\n\nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>If a pin is in the OUPUT\/LOW state, the connected LED lights up. Instead of switching it off by changing to INPUT\/LOW, you can achieve the same result by switching to OUTPUT\/HIGH. <\/p>\n\n<h3 class=\"wp-block-heading\" id=\"MCP23S18\">MCP23S18<\/h3>\n\n<h4 class=\"wp-block-heading\">Pinout<\/h4>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-516x1024.png\"><img loading=\"lazy\" decoding=\"async\" width=\"516\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-516x1024.png\" alt=\"\" class=\"wp-image-14374\" style=\"width:129px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-516x1024.png 516w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-151x300.png 151w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-768x1524.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout-774x1536.png 774w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23S18_pinout.png 865w\" sizes=\"auto, (max-width: 516px) 100vw, 516px\" \/><\/a><\/figure>\n<\/div>\n<p>The MCP23S18 offers no big surprises. It is simply the SPI version of the MCP23018. Unlike the MCP23S17, however, it does not have the option of being addressed with different addresses. Accordingly, you must connect each individual MCP23S18 to its own CS line.   <\/p>\n<p>Nevertheless, the MCP23S18 expects a &#8220;device opcode&#8221; consisting of 0x20 and the read\/write bit as the first byte for write or read operations. The library takes care of this. However, when creating the MCP23S18 object, you must always pass 0x20 (MCP_SPI_CTRL_BYTE) as well. This is simply for compatibility reasons.   <\/p>\n\n<h4 class=\"wp-block-heading\">Example circuit<\/h4>\n\n<p>For the sake of completeness, here is the example circuit:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-1024x636.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"636\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-1024x636.png\" alt=\"The MCP23S18 connected to an Arduino Nano\" class=\"wp-image-14445\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-1024x636.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-300x186.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-768x477.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-1536x954.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano-1320x820.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23s18_wiring_ard_nano.png 1568w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The MCP23S18 connected to an Arduino Nano<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">Example sketch<\/h4>\n\n<p>The example sketch is not surprising.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"MCP23S18_example.ino\" data-enlighter-title=\"MCP23S18_example.ino\">#include &lt;SPI.h&gt;\n#include &lt;MCP23S18_WE.h&gt;\n#define CS_PIN 7   \/\/ Chip Select Pin\n#define RESET_PIN 5 \n#define MCP_SPI_CTRL_BYTE 0x20 \/\/ Do not change\n\n\/* There are two ways to create your MCP23S18 object:\n * MCP23S18_WE myMCP = MCP23S18_WE(CS_PIN, RESET_PIN, MCP_CTRL_BYTE);\n * MCP23S18_WE myMCP = MCP23S18_WE(&amp;SPI, CS_PIN, RESET_PIN, MCP_CTRL_BYTE);\n * The second option allows you to create your own SPI objects,\n * e.g. in order to use two SPI interfaces on the ESP32.\n *\/\ntypedef MCP23S18_WE MCP;\nMCP myMCP = MCP(CS_PIN, RESET_PIN, MCP_SPI_CTRL_BYTE); \/\/ short version\n\/\/ MCP23S18_WE myMCP = MCP23S18_WE(CS_PIN, RESET_PIN, MCP_SPI_CTRL_BYTE); \/\/ long version\n\nint wT = 500; \/\/ wT = waiting time\n\nvoid setup(){ \n  SPI.begin();\n  myMCP.Init(); \n  \/\/ myMCP.setSPIClockSpeed(8000000); \/\/ Choose SPI clock speed (after Init()!)\n  delay(wT);\n  myMCP.setAllPins(MCP::A, MCP::OFF);    \/\/ Port A: all pins are LOW\n  myMCP.setAllPins(MCP::B, MCP::OFF);    \/\/ Port B: all Pins are LOW\n  myMCP.setPortMode(0b11111111, MCP::A); \/\/ Port A: all pins are OUTPUT = LEDs are on!\n  myMCP.setPortMode(0b11111111, MCP::B); \/\/ Port B: all pins are OUTPUT\n  delay(wT);\n  myMCP.setPortMode(0b00000000, MCP::A); \/\/ Port A: all pins are INPUT = LEDs are off\n  myMCP.setPortMode(0b00000000, MCP::B); \/\/ Port B: all pins are INPUT\n  delay(wT);\n  byte portModeValue = 0; \/\/ = 0b00000000\n  for(int i=0; i&lt;8; i++){\n    portModeValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPortMode(portModeValue, MCP::A);\n    delay(wT);\n  }\n  portModeValue = 0;\n  for(int i=0; i&lt;8; i++){\n    portModeValue += (1&lt;&lt;i); \/\/ 0b00000001, 0b00000011, 0b00000111, etc.\n    myMCP.setPortMode(portModeValue, MCP::B);\n    delay(wT);\n  }\n  myMCP.setPortMode(0, MCP::A);          \/\/ Port A: all pins are INPUT\n  myMCP.setPortMode(0, MCP::B);          \/\/ Port B: all pins are INPUT \n  delay(wT);\n  myMCP.setPinMode(3, MCP::A, OUTPUT);   \/\/ Pin 3 \/ PORT A is OUTPUT\/LOW\n  myMCP.setPinMode(1, MCP::B, OUTPUT);   \/\/ Pin 1 \/ PORT B is OUTPUT\/LOW\n  delay(wT);\n  myMCP.setPortMode(0, MCP::A);          \/\/ Port A: all pins are INPUT\n  myMCP.setPortMode(0, MCP::B);          \/\/ Port B: all pins are INPUT\n  myMCP.setPinX(1, MCP::A, OUTPUT, LOW); \/\/ A1 HIGH \n  delay(wT);\n  myMCP.togglePin(1, MCP::A);            \/\/ A1 LOW\n  delay(wT);  myMCP.togglePin(1, MCP::A);\/\/ A1 HIGH\n  delay(wT); \n  \/\/ the following two lines are similar to setPinX(2,MCP::B,OUTPUT,LOW);\n  myMCP.setPinMode(2, MCP::B, OUTPUT);     \/\/ B2 is OUTPUT\/LOW\n  myMCP.setPin(2, MCP::B, LOW);            \/\/ B2 is still OUTPUT\/LOW\n  delay(wT); \n  myMCP.setPortX(0b10001111, 0b10000000, MCP::B); \/\/ B0-B4: OUTPUT\/LOW, B7: OUTPUT, HIGH;\n}\n\nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<h3 class=\"wp-block-heading\" id=\"MCP23016\">MCP23016<\/h3>\n\n<h4 class=\"wp-block-heading\">Pinout<\/h4>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-514x1024.png\"><img loading=\"lazy\" decoding=\"async\" width=\"514\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-514x1024.png\" alt=\"\" class=\"wp-image-14381\" style=\"width:129px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-514x1024.png 514w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-151x300.png 151w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-768x1531.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout-771x1536.png 771w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/mcp23016_pinout.png 865w\" sizes=\"auto, (max-width: 514px) 100vw, 514px\" \/><\/a><\/figure>\n<\/div>\n<p>As you can see on the right, the MCP23016 stands out from the other members of the MCP23x1y family. The GPIOs are named differently, and there is no reset pin. There is also a CLK and TP pin.  <\/p>\n<p>CLK must be connected to GND via a capacitor and to VDD via a resistor. This is used to set the clock speed. The data sheet recommends a combination of 33 pF \/ 3.9 k\u03a9. I also had success with 30 pF \/ 3.9 k\u03a9.    You can check the clock signal at TP, otherwise leave it unconnected. <\/p>\n<p>The biggest difference to the other family members is its different register architecture. Since it is no longer recommended, I decided not to implement it in my library. Instead, I tried out the CyMCP23016 library, which you can find <a href=\"https:\/\/github.com\/cyrusbuilt\/CyMCP23016\" target=\"_blank\" rel=\"noopener\">here<\/a> on GitHub. Overall, the selection of libraries for the MCP23016 is not huge.   <\/p>\n\n<h4 class=\"wp-block-heading\">Example circuit with an Arduino Nano<\/h4>\n\n<p>The CyMCP23016 library comes with a sample sketch, which I tested with the following circuit. In the sketch, only one LED is connected to GPIO 0.0. However, this is sufficient to illustrate the principle. I will not display the sketch here.   <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-1024x469.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"469\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-1024x469.png\" alt=\"The MCP23016 on an Arduino Nano\" class=\"wp-image-14433\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-1024x469.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-300x137.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-768x352.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-1536x703.png 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring-1320x604.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/MCP23016__I2C_test_wiring.png 1566w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The MCP23016 on an Arduino Nano<\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\" id=\"Geschwindigkeitstests\">I2C vs. SPI \u2013 speed tests<\/h2>\n\n<p>When I personally have the choice between I2C and SPI, I tend to favour I2C because fewer wires are required. This is especially true when multiple devices need to be controlled. However, SPI has the edge in applications that require high transmission speeds. I conducted a few tests to investigate this.   <\/p>\n\n<h3 class=\"wp-block-heading\" id=\"I2C_nano\">I2C using the Arduino Nano<\/h3>\n\n<p>The MCP23017 supports an I2C clock speed of 1.7 MHz, while the MCP23018 supports up to 3.4 MHz. The problem, however, is that most microcontrollers do not support these high clock speeds, including ATmega328P-based Arduinos such as the UNO, Nano or Pro Mini. I tested 100 kHz (standard) and 400 kHz (Fast I2C) on the Arduino Nano.   To do this, I determined the time it takes to read a port 10,000 times (<code>digitalRead()<\/code> for an entire port, so to speak). <\/p>\n<p>Here is the sketch:<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"I2C_speed_test_mcp23017_nano.ino\" data-enlighter-title=\"I2C_speed_test_mcp23017_nano.ino\">#include &lt;Wire.h&gt;\n#include &lt;MCP23017_WE.h&gt;\n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n#define RESET_PIN 5  \n\ntypedef MCP23017_WE MCP;\nMCP myMCP = MCP(MCP_ADDRESS, RESET_PIN);\n\nvoid setup(){ \n  Serial.begin(115200);\n  long startTime = 0;\n  long readTime = 0;\n  byte portStatus = 0;\n  Wire.begin();\n  myMCP.Init();  \n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@100kHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@100kHz per Read [ms]: \");\n  Serial.println(readTime\/10000.0);\n\n  Wire.setClock(400000);\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@400kHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@400kHz per Read [ms]: \");\n  Serial.println(readTime\/10000.0);\n}\n    \nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>And here&#8217;s the result:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_ardu_nano.png\"><img loading=\"lazy\" decoding=\"async\" width=\"801\" height=\"182\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_ardu_nano.png\" alt=\"Output of I2C_speed_test_mcp23017_nano.ino\" class=\"wp-image-14396\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_ardu_nano.png 801w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_ardu_nano-300x68.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_ardu_nano-768x175.png 768w\" sizes=\"auto, (max-width: 801px) 100vw, 801px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of I2C_speed_test_mcp23017_nano.ino<\/figcaption><\/figure>\n<\/div>\n<h3 class=\"wp-block-heading\" id=\"I2C_esp32\">I2C using the ESP32<\/h3>\n\n<p>Dann habe ich den Test mit dem ESP32 wiederholt und dabei versucht, 1.7 MHz einzustellen, da ich meinte, der ESP32 k\u00f6nne das.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"I2C_speed_test_mcp23017_esp32.ino\" data-enlighter-title=\"I2C_speed_test_mcp23017_esp32.ino\">#include &lt;Wire.h&gt;\n#include &lt;MCP23017_WE.h&gt;\n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n#define RESET_PIN 18  \n\ntypedef MCP23017_WE MCP;\nMCP myMCP = MCP(MCP_ADDRESS, RESET_PIN);\n\nvoid setup(){ \n  Serial.begin(115200);\n  long startTime = 0;\n  long readTime = 0;\n  byte portStatus = 0;\n  Wire.begin();\n  myMCP.Init();  \n  \n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@100kHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@100kHz per Read [ms]: \");\n  Serial.println(readTime\/10000.0);\n\n  Wire.setClock(400000);\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@400kHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@400kHz per Read [ms]: \");\n  Serial.println(readTime\/10000.0);\n\n  Wire.setClock(1700000);\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@1.7MHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@1.7MHz per Read [ms]: \");\n  Serial.println(readTime\/10000.0);\n}\n  \nvoid loop(){ \n} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>Der magere Geschwindigkeitszuwachs bei 1.7 MHz wunderte mich zun\u00e4chst:&nbsp;<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"730\" height=\"213\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_esp32.png\" alt=\"Output of I2C_speed_test_mcp23017_esp32.ino\" class=\"wp-image-14402\" style=\"width:730px;height:213px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_esp32.png 730w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_i2C_esp32-300x88.png 300w\" sizes=\"auto, (max-width: 730px) 100vw, 730px\" \/><figcaption class=\"wp-element-caption\">Output of I2C_speed_test_mcp23017_esp32.ino<\/figcaption><\/figure>\n<\/div>\n<p>However, measuring the actual clock rate with the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/logic-analyzer\" target=\"_blank\" rel=\"noopener\">logic analyzer<\/a> revealed that even the ESP32 cannot deliver the 1.7 MHz clock rate. It stopped at 655 kHz. This (roughly) corresponds to what I have found elsewhere on the subject, e.g. <a href=\"https:\/\/github.com\/espressif\/arduino-esp32\/issues\/4505\" target=\"_blank\" rel=\"noopener\">here<\/a> on GitHub.  <\/p>\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/max_I2C_speed_ESP32.png\"><img loading=\"lazy\" decoding=\"async\" width=\"947\" height=\"170\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/max_I2C_speed_ESP32.png\" alt=\"\" class=\"wp-image-14400\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/max_I2C_speed_ESP32.png 947w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/max_I2C_speed_ESP32-300x54.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/max_I2C_speed_ESP32-768x138.png 768w\" sizes=\"auto, (max-width: 947px) 100vw, 947px\" \/><\/a><figcaption class=\"wp-element-caption\">Actual I2C clock using the ESP32<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"SPI_nano\">SPI using Arduino Nano <\/h3>\n\n<p>The Arduino Nano and all other boards based on the ATmega328P can deliver an SPI clock rate of up to 16 MHz. The MCP23S17 can handle an SPI clock rate of 10 MHz. However, you cannot set 10 MHz on the Arduino Nano, only quotients of 16 MHz and integer divisors, i.e. 8 MHz, 4 MHz, 2 MHz, etc. 8 MHz is therefore the maximum. If you specify other values, the next possible lower frequency will be used.   <\/p>\n\n<p>This is the sketch:<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"SPI_speed_test_mcp23S17_nano.ino\" data-enlighter-title=\"SPI_speed_test_mcp23S17_nano.ino\">#include &lt;SPI.h&gt;\n#include &lt;MCP23S17_WE.h&gt;\n#define CS_PIN 7   \/\/ Chip Select Pin\n#define RESET_PIN 5 \n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n\ntypedef MCP23S17_WE MCP;\nMCP myMCP = MCP(CS_PIN, RESET_PIN, MCP_ADDRESS);\n\nvoid setup(){ \n  Serial.begin(115200);\n  long startTime = 0;\n  long readTime = 0;\n  byte portStatus;\n  SPI.begin();\n  myMCP.Init(); \n  \n  myMCP.setSPIClockSpeed(2000000); \/\/ Choose SPI clock speed (after Init()!\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@2MHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@2MHz per Read [\u00b5s]: \");\n  Serial.println(readTime\/10.0);\n  \n  myMCP.setSPIClockSpeed(4000000); \/\/ Choose SPI clock speed (after Init()!)\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@4MHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@4MHz per Read [\u00b5s]: \");\n  Serial.println(readTime\/10.0);\n\n  myMCP.setSPIClockSpeed(8000000);\n  startTime = millis();\n  for(long i=0; i&lt;10000; i++){\n    portStatus = myMCP.getPort(MCP::A);\n  }\n  readTime = millis() - startTime;\n  Serial.print(\"Duration@8MHz [ms]: \");\n  Serial.println(readTime);\n  Serial.print(\"Duration@8MHz per Read [\u00b5s]: \");\n  Serial.println(readTime\/10.0);\n}\n  \nvoid loop(){} <\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>And here&#8217;s the result:<\/p>\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"747\" height=\"205\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_spi_nano.png\" alt=\"\" class=\"wp-image-14405\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_spi_nano.png 747w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/speed_test_spi_nano-300x82.png 300w\" sizes=\"auto, (max-width: 747px) 100vw, 747px\" \/><\/figure>\n\n<p>When using an ATmega328P-based board, you can achieve almost ten times the read rate by switching from the MCP23017 to the MCP23S17.<\/p>\n<p>Reading out the Arduino&#8217;s own pins is still much faster. A <code>digitalRead()<\/code> only takes about 3.5 \u00b5s on the Arduino Nano. And reading out the PINB\/PIND registers directly is even faster. This only takes about 0.44 \u00b5s. For details, see my post on <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/logical-operations-and-port-manipulation\" target=\"_blank\" rel=\"noopener\">port manipulation<\/a>.    <\/p>\n\n<h4 class=\"wp-block-heading\">Maximum &#8220;toggle&#8221; speed <\/h4>\n\n<p>Last but not least, I tried to see how quickly a GPIO of the MCP23S17 can be switched back and forth between HIGH and LOW (&#8220;toggle&#8221;). I selected pin A1 and ran the following short sketch on the Arduino Nano: <\/p>\n<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"SPI_gpio_toggle_test_mcp23S17_nano.ino\" data-enlighter-title=\"SPI_gpio_toggle_test_mcp23S17_nano.ino\">#include &lt;SPI.h&gt;\n#include &lt;MCP23S17_WE.h&gt;\n#define CS_PIN 7   \/\/ Chip Select Pin\n#define RESET_PIN 5 \n#define MCP_ADDRESS 0x20 \/\/ (A2\/A1\/A0 = LOW)\n\ntypedef MCP23S17_WE MCP;\nMCP myMCP = MCP(CS_PIN, RESET_PIN, MCP_ADDRESS);\n\nvoid setup(){ \n  Serial.begin(115200);\n  SPI.begin();\n  myMCP.Init();\n  myMCP.setSPIClockSpeed(8000000);\n  myMCP.setPinX(1, MCP::A, OUTPUT, LOW);\n}\n  \nvoid loop(){ \n  myMCP.setPort(0b00000010, MCP::A);\n  myMCP.setPort(0, MCP::A);\n} <\/pre>\n<p>\u00a0<\/p>\n<p>\n\n<p>The maximum frequency is approximately 16 kHz. By comparison, digitalRead() achieves 127 kHz, and port manipulation even achieves approximately 2.3 MHz. <\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/pin_toggle_mcp23S17_8mhz.png\"><img loading=\"lazy\" decoding=\"async\" width=\"633\" height=\"119\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/pin_toggle_mcp23S17_8mhz.png\" alt=\"Maximum &quot;toggle&quot; frequency with the MCP23S17 on the Arduino Nano\" class=\"wp-image-14413\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/pin_toggle_mcp23S17_8mhz.png 633w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/04\/pin_toggle_mcp23S17_8mhz-300x56.png 300w\" sizes=\"auto, (max-width: 633px) 100vw, 633px\" \/><\/a><figcaption class=\"wp-element-caption\">Maximum &#8220;toggle&#8221; frequency with the MCP23S17 on the Arduino Nano<\/figcaption><\/figure>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show you how to control them.<\/p>\n","protected":false},"author":1,"featured_media":14955,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[565,566],"tags":[556,605,1803,558,1802,665,1800,1541,1801,1497,1804],"class_list":["post-14940","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-other-parts","category-port-expansion","tag-arduino-en-2","tag-example-sketch","tag-i2c-vs-spi-en","tag-library-en-2","tag-mcp23016-en","tag-mcp23017-en","tag-mcp23018-en","tag-mcp23s17-en","tag-mcp23s18-en","tag-pinout-en","tag-speed-tests"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>MCP23x1y Port Expander &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MCP23x1y Port Expander &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2022-06-16T16:12:26+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-08T11:51:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1022\" \/>\n\t<meta property=\"og:image:height\" content=\"1023\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"24 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"MCP23x1y Port Expander\",\"datePublished\":\"2022-06-16T16:12:26+00:00\",\"dateModified\":\"2026-03-08T11:51:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander\"},\"wordCount\":2588,\"commentCount\":8,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Beitragsbild_MCP23x1y.jpg\",\"keywords\":[\"Arduino\",\"Example sketch\",\"I2C vs. SPI\",\"Library\",\"MCP23016\",\"MCP23017\",\"MCP23018\",\"MCP23S17\",\"MCP23S18\",\"Pinout\",\"Speed tests\"],\"articleSection\":[\"Other parts\",\"Port expansion\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander\",\"name\":\"MCP23x1y Port Expander &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Beitragsbild_MCP23x1y.jpg\",\"datePublished\":\"2022-06-16T16:12:26+00:00\",\"dateModified\":\"2026-03-08T11:51:54+00:00\",\"description\":\"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Beitragsbild_MCP23x1y.jpg\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Beitragsbild_MCP23x1y.jpg\",\"width\":1022,\"height\":1023},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/mcp23x1y-port-expander#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MCP23x1y Port Expander\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MCP23x1y Port Expander &#8226; Wolles Elektronikkiste","description":"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander","og_locale":"en_US","og_type":"article","og_title":"MCP23x1y Port Expander &#8226; Wolles Elektronikkiste","og_description":"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander","og_site_name":"Wolles Elektronikkiste","article_published_time":"2022-06-16T16:12:26+00:00","article_modified_time":"2026-03-08T11:51:54+00:00","og_image":[{"width":1022,"height":1023,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg","type":"image\/jpeg"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"24 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"MCP23x1y Port Expander","datePublished":"2022-06-16T16:12:26+00:00","dateModified":"2026-03-08T11:51:54+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander"},"wordCount":2588,"commentCount":8,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg","keywords":["Arduino","Example sketch","I2C vs. SPI","Library","MCP23016","MCP23017","MCP23018","MCP23S17","MCP23S18","Pinout","Speed tests"],"articleSection":["Other parts","Port expansion"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander","url":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander","name":"MCP23x1y Port Expander &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg","datePublished":"2022-06-16T16:12:26+00:00","dateModified":"2026-03-08T11:51:54+00:00","description":"I compare the members of the MCP23x1y family: MCP23016, MCP23017, MCP23S17, MCP23018, MCP23S18 and show how to control them.","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/06\/Beitragsbild_MCP23x1y.jpg","width":1022,"height":1023},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/mcp23x1y-port-expander#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"MCP23x1y Port Expander"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/14940","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=14940"}],"version-history":[{"count":6,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/14940\/revisions"}],"predecessor-version":[{"id":25759,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/14940\/revisions\/25759"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/14955"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=14940"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=14940"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=14940"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}