<h3>Contribution description</h3>
<p>This PR adds a driver module for the widespread PCF857X serial I/O expander modules which extend the number of GPIOs over the I2C bus. The following expander modules are supported by the driver:</p>
<ul>
<li>PCF8574 and PCF857A 8-bit I2C I/O expander with 1 port with 8 input/output pins</li>
<li>PCF8575 16-bit I2C I/O expander with 2 ports with 8 input/output pins each</li>
</ul>
<p>The driver defines the driver variants by a pseudomodule for each of supported expander module:</p>
<ul>
<li><code>pcf8574 </code> for PCF8574</li>
<li><code>pcf8574a</code> for PCF8574A</li>
<li><code>pcf8575 </code> for PCF8575</li>
</ul>
<p>The driver interface is kept as compatible as possible with the peripheral GPIO interface. The only difference is that the functions have the prefix <code>pcf857x_</code> and require an additional parameter, the pointer to the expansion device of type <code>pcf857x_t</code></p>
<p>Since PCF857X expander pins are only quasi-bidirectional without having a separate direction control signal, they only support active LOW driven outputs and inputs that are pulled up to HIGH. HIGH outputs are nothing else than pulled-up inputs. The driver maps this behavior to the <code>GPIO_IN_PU</code> and <code>GPIO_OD</code> and additionally to the <code>GPIO_IN</code>, <code>GPIO_OUT</code> and <code>GPIO_OD_PU</code> modes.</p>
<p>Optionally, the driver can use the low-active open-drain INT signal of PCF857x expander modules</p>
<ul>
<li>to provide external interrupt capabilities for all expander pins which are compatible to module <code>periph_gpio_irq</code></li>
<li>to keep internal up-to-state of expander inputs to avoid reading expander input pins via I2C each time a single input value read with <code>pcf857x_gpio_read</code>, see the benchmarks.</li>
</ul>
<p>The driver support direct GPIO mapping to SAUL with is compatible to the peripheral GPIO SAUL interface. Thus PCF857X I/O expander pins can be used with SAUL in the same was as peripheral GPIOS.</p>
<h2>Benchmarks</h2>
<p>The performance of the driver strongly depends on using interrupt capabilities or not:</p>
<ul>
<li>PCF857X driver run-time performance benchmark without interrupt capabilities @ 400 kHz I2C bus speed:</li>
</ul>
<pre><code>                 nop loop:       639us  ---   0.063us per call  ---   15649452 calls per sec
                 gpio_set:    842995us  ---  84.299us per call  ---      11862 calls per sec
               gpio_clear:    840009us  ---  84.000us per call  ---      11904 calls per sec
              gpio_toggle:    842000us  ---  84.200us per call  ---      11876 calls per sec
                gpio_read:    877514us  ---  87.751us per call  ---      11395 calls per sec
               gpio_write:    841430us  ---  84.143us per call  ---      11884 calls per sec
</code></pre>
<ul>
<li>PCF857X driver run-time performance benchmark with interrupt capabilities (module <code>periph_gpio_irq</code>)  @ 400 kHz I2C bus speed:</li>
</ul>
<pre><code>                 nop loop:       626us  ---   0.062us per call  ---   15974440 calls per sec
                 gpio_set:   1751632us  ---  175.163us per call  ---       5708 calls per sec
               gpio_clear:   1755016us  ---  175.501us per call  ---       5697 calls per sec
              gpio_toggle:   1755082us  ---  175.508us per call  ---       5697 calls per sec
                gpio_read:      4751us  ---   0.475us per call  ---    2104820 calls per sec
               gpio_write:   1759999us  ---  175.999us per call  ---       5681 calls per sec
</code></pre>
<p>Reference board was an <code>esp8266-esp-12x</code> in IC2 fast mode.</p>
<h3>Testing procedure</h3>
<p>The test application <code>tests/driver_pcf857x</code> can be used to test each PCF857X expander I/O pin with shell commands. It bases on the test application for GPIO peripheral drivers.</p>
<p>To use the test application, just compile it with one of the pseudomodules<br>
<code>pcf8574</code>, <code>pcf8574a</code> or `pcf8575, e.g.</p>
<pre><code> USEMODULE=pcf8575 make flash -C tests/driver_pcf857x BOARD=...
</code></pre>
<p>Add module <code>periph_gpio_irq</code> and define the MCU interrupt pin by parameter  PCF857X_PARAM_INT_PIN` to use the PCF857X interrupt signal, e.g.,</p>
<pre><code> CFLAGS="-DPCF857X_PARAM_INT_PIN=\(GPIO\(0,6\)\)" \
 USEMODULE="pcf8575 periph_gpio_irq" make 
</code></pre>
<h3>Issues/PRs references</h3>
<p>Beside the PCF857X expanders, there are many more expansion modules. An attempt has already been made to add a driver for the MCP23017 16-bit I2C I/O expander with PR <a class="issue-link js-issue-link" data-error-text="Failed to load issue title" data-id="261249222" data-permission-text="Issue title is private" data-url="https://github.com/RIOT-OS/RIOT/issues/7652" data-hovercard-type="pull_request" data-hovercard-url="/RIOT-OS/RIOT/pull/7652/hovercard" href="https://github.com/RIOT-OS/RIOT/pull/7652">#7652</a>. With the 16-bit MCP23S17 SPI I/O expander there is a GPIO expander that allows faster access with up to 10 MHz.</p>
<p>Perhaps there should be a general management architecture for modules that provide access to GPIOs, for example a registry for GPIO providers with a common access interface. Every GPIO provider would need to register with its meta information. If the MCU were also considered as a GPIO provider, all GPIOs could be used over the same interface, regardless of whether it is provided by the MCU or an GPIO expander.</p>

<hr>

<h4>You can view, comment on, or merge this pull request online at:</h4>
<p>  <a href='https://github.com/RIOT-OS/RIOT/pull/10430'>https://github.com/RIOT-OS/RIOT/pull/10430</a></p>

<h4>Commit Summary</h4>
<ul>
  <li>doc: add I/O expanders to drivers_periph group</li>
  <li>drivers: add PCF857X I/O expander driver</li>
  <li>sys/auto_init: add PCF857X SAUL initialization</li>
  <li>makefiles: add PCF957X driver pseudomodules</li>
  <li>tests: add PCF957X driver test application</li>
</ul>

<h4>File Changes</h4>
<ul>
  <li>
    <strong>M</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-0">drivers/Makefile.dep</a>
    (24)
  </li>
  <li>
    <strong>M</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-1">drivers/Makefile.include</a>
    (4)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-2">drivers/include/pcf857x.h</a>
    (418)
  </li>
  <li>
    <strong>M</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-3">drivers/include/periph/doc.txt</a>
    (10)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-4">drivers/pcf857x/Makefile</a>
    (1)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-5">drivers/pcf857x/include/pcf857x_params.h</a>
    (109)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-6">drivers/pcf857x/pcf857x.c</a>
    (416)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-7">drivers/pcf857x/pcf857x_saul.c</a>
    (57)
  </li>
  <li>
    <strong>M</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-8">makefiles/pseudomodules.inc.mk</a>
    (6)
  </li>
  <li>
    <strong>M</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-9">sys/auto_init/auto_init.c</a>
    (4)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-10">sys/auto_init/saul/auto_init_pcf857x.c</a>
    (107)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-11">tests/driver_pcf857x/Makefile</a>
    (11)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-12">tests/driver_pcf857x/README.md</a>
    (25)
  </li>
  <li>
    <strong>A</strong>
    <a href="https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-13">tests/driver_pcf857x/main.c</a>
    (324)
  </li>
</ul>

<h4>Patch Links:</h4>
<ul>
  <li><a href='https://github.com/RIOT-OS/RIOT/pull/10430.patch'>https://github.com/RIOT-OS/RIOT/pull/10430.patch</a></li>
  <li><a href='https://github.com/RIOT-OS/RIOT/pull/10430.diff'>https://github.com/RIOT-OS/RIOT/pull/10430.diff</a></li>
</ul>

<p style="font-size:small;-webkit-text-size-adjust:none;color:#666;">—<br />You are receiving this because you are subscribed to this thread.<br />Reply to this email directly, <a href="https://github.com/RIOT-OS/RIOT/pull/10430">view it on GitHub</a>, or <a href="https://github.com/notifications/unsubscribe-auth/AEn7YD-zu-YKzK5y-KUw4pDxK0fJj7qyks5uws9MgaJpZM4YpWEK">mute the thread</a>.<img src="https://github.com/notifications/beacon/AEn7YEkSZz_Qm9dLx4bkyCEkWMIGa28lks5uws9MgaJpZM4YpWEK.gif" height="1" width="1" alt="" /></p>
<script type="application/json" data-scope="inboxmarkup">{"api_version":"1.0","publisher":{"api_key":"05dde50f1d1a384dd78767c55493e4bb","name":"GitHub"},"entity":{"external_key":"github/RIOT-OS/RIOT","title":"RIOT-OS/RIOT","subtitle":"GitHub repository","main_image_url":"https://assets-cdn.github.com/images/email/message_cards/header.png","avatar_image_url":"https://assets-cdn.github.com/images/email/message_cards/avatar.png","action":{"name":"Open in GitHub","url":"https://github.com/RIOT-OS/RIOT"}},"updates":{"snippets":[{"icon":"DESCRIPTION","message":"drivers: add PCF857X I2C I/O expander driver (#10430)"}],"action":{"name":"View Pull Request","url":"https://github.com/RIOT-OS/RIOT/pull/10430"}}}</script>
<script type="application/ld+json">[
{
"@context": "http://schema.org",
"@type": "EmailMessage",
"potentialAction": {
"@type": "ViewAction",
"target": "https://github.com/RIOT-OS/RIOT/pull/10430",
"url": "https://github.com/RIOT-OS/RIOT/pull/10430",
"name": "View Pull Request"
},
"description": "View this Pull Request on GitHub",
"publisher": {
"@type": "Organization",
"name": "GitHub",
"url": "https://github.com"
}
},
{
"@type": "MessageCard",
"@context": "http://schema.org/extensions",
"hideOriginalBody": "false",
"originator": "AF6C5A86-E920-430C-9C59-A73278B5EFEB",
"title": "drivers: add PCF857X I2C I/O expander driver (#10430)",
"sections": [
{
"text": "",
"activityTitle": "**Gunar Schorcht**",
"activityImage": "https://assets-cdn.github.com/images/email/message_cards/avatar.png",
"activitySubtitle": "@gschorcht",
"facts": [

]
},
{
"title": "Commit Summary",
"facts": [
{
"name": "b73b110",
"value": "doc: add I/O expanders to drivers_periph group"
},
{
"name": "fdcedca",
"value": "drivers: add PCF857X I/O expander driver"
},
{
"name": "f4e914b",
"value": "sys/auto_init: add PCF857X SAUL initialization"
},
{
"name": "54fafdc",
"value": "makefiles: add PCF957X driver pseudomodules"
},
{
"name": "efc3c7f",
"value": "tests: add PCF957X driver test application"
}
]
},
{
"title": "File Changes",
"facts": [
{
"name": "Modified",
"value": "[drivers/Makefile.dep](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-0) (24 changes)"
},
{
"name": "Modified",
"value": "[drivers/Makefile.include](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-1) (4 changes)"
},
{
"name": "Added",
"value": "[drivers/include/pcf857x.h](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-2) (418 changes)"
},
{
"name": "Modified",
"value": "[drivers/include/periph/doc.txt](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-3) (10 changes)"
},
{
"name": "Added",
"value": "[drivers/pcf857x/Makefile](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-4) (1 changes)"
},
{
"name": "Added",
"value": "[drivers/pcf857x/include/pcf857x_params.h](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-5) (109 changes)"
},
{
"name": "Added",
"value": "[drivers/pcf857x/pcf857x.c](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-6) (416 changes)"
},
{
"name": "Added",
"value": "[drivers/pcf857x/pcf857x_saul.c](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-7) (57 changes)"
},
{
"name": "Modified",
"value": "[makefiles/pseudomodules.inc.mk](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-8) (6 changes)"
},
{
"name": "Modified",
"value": "[sys/auto_init/auto_init.c](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-9) (4 changes)"
},
{
"name": "Added",
"value": "[sys/auto_init/saul/auto_init_pcf857x.c](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-10) (107 changes)"
},
{
"name": "Added",
"value": "[tests/driver_pcf857x/Makefile](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-11) (11 changes)"
},
{
"name": "Added",
"value": "[tests/driver_pcf857x/README.md](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-12) (25 changes)"
},
{
"name": "Added",
"value": "[tests/driver_pcf857x/main.c](https://github.com/RIOT-OS/RIOT/pull/10430/files#diff-13) (324 changes)"
}
]
}
],
"potentialAction": [
{
"name": "Add a comment",
"@type": "ActionCard",
"inputs": [
{
"isMultiLine": true,
"@type": "TextInput",
"id": "IssueComment",
"isRequired": false
}
],
"actions": [
{
"name": "Comment",
"@type": "HttpPOST",
"target": "https://api.github.com",
"body": "{\n\"commandName\": \"IssueComment\",\n\"repositoryFullName\": \"RIOT-OS/RIOT\",\n\"issueId\": 10430,\n\"IssueComment\": \"{{IssueComment.value}}\"\n}"
}
]
},
{
"name": "Close pull request",
"@type": "HttpPOST",
"target": "https://api.github.com",
"body": "{\n\"commandName\": \"PullRequestClose\",\n\"repositoryFullName\": \"RIOT-OS/RIOT\",\n\"pullRequestId\": 10430\n}"
},
{
"targets": [
{
"os": "default",
"uri": "https://github.com/RIOT-OS/RIOT/pull/10430"
}
],
"@type": "OpenUri",
"name": "View on GitHub"
},
{
"targets": [
{
"os": "default",
"uri": "https://github.com/RIOT-OS/RIOT/pull/10430.patch"
}
],
"@type": "OpenUri",
"name": "View patch"
},
{
"targets": [
{
"os": "default",
"uri": "https://github.com/RIOT-OS/RIOT/pull/10430.diff"
}
],
"@type": "OpenUri",
"name": "View diff"
},
{
"name": "Unsubscribe",
"@type": "HttpPOST",
"target": "https://api.github.com",
"body": "{\n\"commandName\": \"MuteNotification\",\n\"threadId\": 413491466\n}"
}
],
"themeColor": "26292E"
}
]</script>