    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Raspberry Pi Linux User Mode GPIO in C++ (Part 3)</title>
        <link>https://members.accu.org/index.php/articles/2166</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + CVu Journal Vol 27, #5 - November 2015</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c77/">CVu</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c355/">275</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-355/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+355/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Raspberry Pi Linux User Mode GPIO in C++ (Part 3)</h1>
<p><strong>Author:</strong>&nbsp;Martin Moene</p>
<p>
<strong>Date:</strong> 07 November 2015 08:59:34 +00:00 or Sat, 07 November 2015 08:59:34 +00:00</p>
<p><strong>Summary:</strong>&nbsp;Ralph McArdell demonstrates the library with two peripherals on the Pi.</p>
<p><strong>Body:</strong>&nbsp;<p>The previous instalments <a href="#[1]">[1</a>, <a href="#[2]">2]</a> have described creating the <code>rpi-peripherals</code> <a href="#[3]">[3]</a> library to access general purpose input output (GPIO) on a Raspberry Pi running Raspbian Linux in C++ from user space. They covered creating the <code>phymem_ptr</code> class template that utilises RAII (resource acquisition is initialisation <a href="#[4]">[4]</a>) to manage mapped areas of physical memory, setting up the library project and the implementation of support for basic general purpose input and output of single bit Boolean values, clocks and pulse with modulation (PWM).</p>

<p>This final instalment describes the two serial interface peripheral types the library supports and closes with some concluding remarks.</p>

<h2>SPI game</h2>

<p>Having added PWM support to the library and played with the Gertboardâ€™s <a href="#[5]">[5]</a> motor controller I turned to the digital to analogue converter (DAC) and analogue to digital converter (ADC) chips. The ADC handles 10-bit samples while the DAC handles 8-bit samples â€“ other Gertboards may have similar DAC chips that handle 10 or 12 bit samples. Both chips use the serial peripheral interface (SPI) <a href="#[6]">[6]</a> to transfer data making the addition of SPI support the next task.</p>

<p>The Raspberry Piâ€™s Broadcom BCM2835 processor has several peripherals that support SPI. For the older Raspberry Pi models I was targeting the GPIO pins provided for interfacing only allow using the SPI0 peripheral â€“ referred to as â€˜SPIâ€™ or â€˜SPI Masterâ€™ in the documentation <a href="#[7]">[7]</a>. As there are also two instances of a â€˜Universal SPI Masterâ€™ or â€˜mini SPI interfaceâ€™ peripheral type named SPI1 and SPI2 I decided to unambiguously use â€˜spi0â€™ to refer to SPI0 peripheral related entities.</p>

<p>SPI uses the common master/slave model <a href="#[8]">[8]</a> where a single master device has control over one or more slave devices. In this case SPI0 on the Raspberry Pi is the master device and the ADC and DAC chips are slave devices. As an aside the BCM2835 also supports an SPI slave peripheral, unavailable on the earlier Raspberry Pi models. The standard communication mode is a â€˜3-wireâ€™ protocol, allowing master and slave to send data simultaneously. Two of the three â€˜wiresâ€™ are for the master to send data to a slave â€“ MOSI (master output, slave input), and for the slave to send data to the master â€“ MISO (master input, slave output). SPI is a synchronous serial interface so the third â€˜wireâ€™, SCLK, is the clock signal which is provided by the master. The master only communicates with one slave device at a time, which device being determined by a number of chip enable (or chip select) lines. The SPI0 peripheral provides two such lines â€“ CE0 and CE1.</p>

<p>For added fun SPI0 supports two 2-wire modes which only use SCLK and MOSI for communication: bidirectional mode which calls MOSI MOMI (master output, master input) and LoSSI (low speed serial interface) mode which names MOSI SDA (serial data) and SCLK SCL (serial clock).</p>

<p>The data transferred between SPI0 and a slave device are a pair of FIFO (first in first out) buffers, one for data to be sent to the slave and the other for data received from the slave. They are 16 32-bit words deep, allowing 64 8-bit bytes to be buffered. The FIFOs are a case where peripheral registers do not behave like regular memory. Both FIFOs are accessed via the same register with reads returning the next available value from the receive FIFO and writes writing to the next available slot in the transmit FIFO.</p>

<p>As with other peripherals I only considered support for SPI0 polled use. On the other hand I did want to support all three communication modes along with various parameters that may need tweaking depending on the specifics of various slave devices.</p>

<h2>A plurality of pins</h2>

<p>Implementing SPI0 support initially followed the pattern discussed in part 2: I started with the <code>spi0_registers</code> class that matched the layout of the SPI0 peripheralâ€™s control registers and allows querying and setting the various fields. I created the <code>spi0_ctrl</code> singleton class which as per the pattern contains the <code>phymem_ptr</code> specialisation <code>phymem_ptr&lt;volatile spi0_registers&gt;</code> member that maps a <code>spi0_registers</code> instance over the SPI0 control registers. As SPI0 only supports a single item the type for the <code>spi0_ctrl</code> is-in-use tracking member is simply a <code>bool</code>.</p>

<p>The pattern dictates there should be a <code>spi0_pin</code> class. SPI0 requires the use of 5 pins, or 4 for the 2-wire modes. Hence the name <code>spi0_pins</code> â€“ plural, was chosen.</p>

<p>It seemed cumbersome to pass in four or five pin value parameters to the <code>spi0_pins</code> constructor, especially considering that for the Raspberry Pi models I was targeting there could only be two possible valid sets of values: either all five of the available pins for SPI0 functions or the four pin subset required for 2 wire bidirectional mode operation. On the other hand I did not want to hard code the pin values as the SPI0 functions are available on a second group of pins and it was possible other BCM2835 based systems could access them.</p>

<p>So the constructor of <code>spi0_pins</code> takes a <code>spi0_pin_set</code> class template specialisation. <code>spi0_pin_set</code> has five integer non-type template parameters â€“ one for each SPI0 pin. The fifth parameter has a default value representing pin-not-used to allow four pin sets to be defined. The class contains no values and only has five member functions â€“ one for each SPI0 pin function â€“ that return the value of the associated template parameter. Two instances are defined: <code>rpi_p1_spi0_full_pin_set</code> that specifies all 5 pins and <code>rpi_p1_spi0_2_wire_only_pin_set</code> that specifies the 4 pin subset required for 2-wire mode operation.</p>

<h2>Chip chat</h2>

<p>I soon realised that having just a <code>spi0_pins</code> class was not sufficient. Adding functionality to <code>spi0_pins</code> to allow checking the various states the FIFOs could be in was not a problem. It was when I came to implement the read and write functionality that I ran into a problem.</p>

<p>SPI0 can directly select one of two devices to converse with and switch conversations between devices. Each device can use different sets of communication parameters, so one <code>spi0_pins</code> instance has be able to support multiple sets of conversation parameters.</p>

<p>My initial solution was to create a <code>spi0_conversation</code> class, instances of which represented conversations with specific devices with the relevant parameters being passed as constructor arguments. To hold a conversation an instance was opened by passing a reference to a <code>spi0_pins</code> object to the <code>open</code> member function. Once successfully opened the conversation could proceed by calling the <code>read</code> and <code>write</code> member functions. When done the <code>close</code> member function was called. Attempting to have more than one open conversation at a time caused an exception to be thrown. Opening a conversation would set the required SPI0 communication parameters, then activate SPI0 data transfers â€“ which were deactivated on conversation close.</p>

<p>This scheme worked but I did not like the low level twiddling with SPI0 registers being split across two classes. Worse, in order to keep track of open conversations the <code>spi0_pins</code> instance had to keep a pointer to the current open <code>spi0_conversation</code> which was set to <code>nullptr</code> on conversation close meaning the <code>spi0_conversation</code> object had to hold a pointer to the <code>spi0_pins</code> object. So instances of each type referenced each other whenever there was an open conversation which seemed somewhat inelegant.</p>

<p>Moving the read and write functionality to <code>spi0_pins</code> solved my first gripe. To address the second gripe I applied conversation contexts to a <code>spi0_pins</code> instance, with member functions <code>spi0_pins::start_conversing</code> and <code>spi0_pins::stop_conversing</code> in place of open and close operations.</p>

<p>This left <code>spi0_conversation</code> with very little to do so I renamed it <code>spi0_slave_context</code>. Instances of <code>spi0_slave_context</code> hold the subset of SPI0 peripheral registers needed to define the context of each conversation. To create the required register values the construction parameters are used to set the relevant field values of a local automatic <code>spi0_registers</code> object from which the required complete register values are copied to instance data members.</p>

<p>To start a conversation a <code>spi0_slave_context</code> instance is passed to <code>spi0_pins::start_conversing</code> which, after stopping any conversation and performing some validation, copies over most of the <code>spi0_slave_context</code> objectâ€™s register value members to their live counterparts. Some fields of the control and status register should not be overwritten so a mask is used to apply only the relevant bits.</p>

<h2>Read and write Ã  la mode</h2>

<p>The read and write operations provided by <code>spi0_pins</code> cater for transferring single and multiple byte values. Single byte operations return a <code>bool</code> indicating whether or not a value was transferred to or from a FIFO. Multi-byte operations return a <code>std::size_t</code> indicating how many bytes were transferred. A transfer may not complete for several reasons: conversing may be stopped or the transmit FIFO is full or the receive FIFO empty.</p>

<p>Which of the three SPI communication modes is used is part of a conversationâ€™s associated <code>spi0_slave_context</code>. The specifics of the protocols used by each mode are mostly hidden behind the <code>read</code> and <code>write</code> member functions, although some modes require extra information for some operations. Luckily these could be supported by appending an additional parameter with a default value to the operations concerned.</p>

<p>The easiest mode to implement, and the only one I could fully test due to the available hardware, was standard 3-wire mode. In standard mode data is written to the transmit FIFO while it is not full and read from the receive FIFO while it is not empty. The only oddity is that in order to read some data you must first write something â€“ anything. So to read two bytes you first write two bytes. As these are transmitted to the slave device its reply is received, appearing in the receive FIFO. Of course serially transferring data takes time so there will be delays involved.</p>

<p>Listing 1 shows an example where a conversation expects two bytes to be received after the slave device has been sent a single byte that sets up the conversation. In the <code>read</code> function, while only one byte is required to be written to setup the conversation the same value is sent twice as we expect to read two bytes. Each byte is then read by calling the <code>read_byte</code> function which waits until data arrives in the receive FIFO, wrapping a call to the single byte overload of <code>spi0_pins::read</code> in a loop with a delay.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
#include &quot;spi0_pins.h&quot;
#include &lt;array&gt;
#include &lt;thread&gt;
#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;iomanip&gt;

using namespace dibase::rpi::peripherals;
unsigned char read_byte(spi0_pins &amp; spi0)
{
  constexpr auto a_short_while
    (std::chrono::microseconds{100});
  unsigned char byte{0U};
  while (!spi0.read(byte))
    std::this_thread::sleep_for(a_short_while);
  return byte;
}
bool read(spi0_pins &amp; spi0,std::array&lt;int,2&gt; &amp; result)
{
  constexpr unsigned char mode{0xd0};
  if (spi0.write(mode) &amp;&amp; spi0.write(mode))
  {
    result[0] = read_byte(spi0);
    result[1] = read_byte(spi0);
    return true;
  }
  return false;
}

int main()
{
  try
  {
    constexpr auto f_sclk(megahertz{1});
    spi0_slave_context chip0_context{
      spi0_slave::chip0, f_sclk};
    spi0_pins spi0{rpi_p1_spi0_full_pin_set};
    for (unsigned i=0; i&lt;10; ++i)
    {
      spi0.start_conversing(chip0_context);
      std::array&lt;int,2&gt; data;
      if (read(spi0,data))
        std::cout &lt;&lt; std::hex 
                  &lt;&lt; std::setfill('0')
                  &lt;&lt; std::setw(2) &lt;&lt; data[0] 
                  &lt;&lt; ' '          &lt;&lt; std::setw(2)
                  &lt;&lt; data[1] &lt;&lt; '\n';
      else
        std::cout &lt;&lt; &quot;## ##\n&quot;;
    }
  }
  catch (std::exception &amp; e)
  {
    std::cerr &lt;&lt; &quot;Failed because: &quot; 
              &lt;&lt; e.what() &lt;&lt; '\n';
  }
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>

<p>In <code>main</code> the <code>spi0_pins</code> and <code>spi0_slave_context</code> objects are created and ten sets of data obtained from the slave device selected by asserting CE0, specified by passing <code>spi0_slave::chip0</code> to the <code>context</code> objectâ€™s constructor. The device requires that each value read is a separate conversation so the call to <code>spi0_pins::start_conversing</code> is inside the loop. The only other value explicitly specified for the slave context is the frequency of the clock, given in terms of the frequency types initially created for the clock peripheralsâ€™ library support described in part 2. To ensure that resources are released should an exception be thrown the whole lot is wrapped in a try-block. The single catch clause for <code>std::exception</code> by reference suffices as the library throws standard library exception types or types derived from them.</p>

<p>SPI standard mode reading and writing is tested using a loop-back configuration connecting the MOSI pin to the MISO pin so each written byte is immediately received back again. The support for reading and writing using the 2-wire modes can at best be termed â€˜provisionalâ€™ as I have not been able to test them. I did not see how I could use a loopback setup with these modes and had no devices to hand that supported them â€“ nor had I come across any in my very limited search for devices.</p>

<h2>I<sup>2</sup>C â€“ a serial interface by many other names</h2>

<p>Having implemented SPI support allowing me to use the DAC and ADC chips on the Gertboard the only remaining device to look at was an Atmel AVR ATmega 8-bit microcontroller which houses a variety of useful interfaces and peripherals. ATmega application programs are stored in non-volatile flash memory and are sent via a supported interface with the microcontroller in a programming mode. On the Gertboard the ATmega microcontroller is programmed over SPI, using SPI0 at the Raspberry Pi end. I contemplated using the microcontroller as a peripheral extender but did not want to dedicate SPI0 permanently to the microcontroller. A browse through the relevant ATmega data sheet <a href="#[9]">[9]</a> revealed a two wire serial interface (TWI) compatible with the Inter-Integrated Circuit (IIC or I<sup>2</sup>C) interface <a href="#[10]">[10]</a> is supported. Thinking this could be used for Raspberry Pi and microcontroller communication I decided to add I<sup>2</sup>C support to the peripherals library.</p>

<p>The peripheral documentation for the BCM2835 calls its I<sup>2</sup>C-like serial interface â€˜Broadcom Serial Controllerâ€™ (BSC). Three BSC master controller peripherals â€“ BSC0, BSC1 and BSC2 are supported but only BSC0 and BSC1 are available for use via appropriately configured GPIO pins, BSC2 being reserved for use with the HDMI interface.</p>

<p>As you may have inferred I<sup>2</sup>C/BSC/TWI uses the master/slave model with each BSC controller acting as an I<sup>2</sup>C master (I<sup>2</sup>C slave mode is supported by the same peripheral that supports SPI slave mode). I<sup>2</sup>C only uses two wires â€“ or pins â€“ referred to as serial data (SDA) and serial clock (SCL). Slave devices have an address which is generally in a 7-bit range, but a cunning scheme can allow 10-bit addressing to be used. This scheme is outlined later. All transfers consist of serialised 8-bit bytes with the master sending an initial start byte containing the 7-bit address of the slave device the master wishes to converse with and a single bit indicating whether the master is reading or writing. Standard I<sup>2</sup>C can communicate at up to 100,000 bits per second (100 Kbps). The BSC controllers support I<sup>2</sup>C fast-mode allowing speeds of up to 400Kbps. Like SPI0 there are various parameters that can be adjusted to ensure master and slaves can communicate â€“ the serial clock frequency value for example. All of these parameters I found could have useful default values but unlike SPI0 they apply to a controller as a whole and not on a per slave device basis.</p>

<p>BSC masters use a single 16 entry 8-bit wide FIFO that is shared by read and write operations as the I<sup>2</sup>C bus cannot be doing both simultaneously. Primarily only polled usage is supported by the BSC masters although interrupts can be generated for some interesting conditions. As with other peripherals the library only supports polled usage.</p>

<h2>As there are only the two pinsâ€¦</h2>

<p>Once again, support for the BSC masters broadly follows the pattern discussed in part 2 with the <code>i2c_registers</code> class matching the layout of the BSC mastersâ€™ control registers and allowing querying and setting the various fields. However, the <code>i2c_ctrl</code> singleton class deviated from the pattern because the BSC mastersâ€™ register blocks are located sufficiently distant from each other that an array of three <code>phymem_ptr&lt;volatile i2c_registers&gt;</code> was required to map three <code>i2c_registers</code> instances over three distinct BSC master register address blocks. As with SPI0, because I<sup>2</sup>C requires more than one pin there is the <code>i2c_pins</code> (plural) class.</p>

<p>I thought two pins were few enough that they could be passed directly to <code>i2c_pins</code> constructors as individual parameters. Annoyingly there is a case where the same two pins support two BSC masters on different alternate pin functions. Although the target Raspberry Pi models do not provide access to these pins I wanted to support this case so provided two constructors. One identifies a BSC master from just two passed <code>pin_id</code> values while the other is additionally passed a disambiguating 0 or 1 value to indicate BSC0 or BSC1 directly. The remaining parameters, common to both constructors, define a bunch of communication parameters and all have defaults.</p>

<h2>Conversation starter</h2>

<p>As I<sup>2</sup>C communications parameters apply to the whole peripheral the conversation state complexity of SPI0 does not apply. The only thing required to talk to a slave device is its 7-bit address, which is sent by the master at the start of a transaction along with a read/write bit. To cater for these transaction start requirements I added <code>start_write</code> and <code>start_read</code> member functions in addition to write and read member functions.</p>

<p>BSC masters require the data (byte) length â€“ in the range [0, 65535] â€“ to be specified at the start of each transaction. The transaction completes when data-length bytes have been transferred. So the BSC master peripherals require a slave device address and a transaction data length to start a transaction. When starting a write transaction it is useful to pass an initial chunk of data to transfer, however immediately after starting a read transaction there is nothing yet to receive.</p>

<p>Only multi-byte transfers are supported by the read and write operations of <code>i2c_pins</code> which return a <code>std::size_t</code> indicating how many bytes were transferred. A transfer may not complete because either the FIFO is full so no more data can be written to it or it is empty and no more data can be read from it. The pattern is to call <code>start_write</code> or <code>start_read</code> followed by repeated calls to <code>write</code> or <code>read</code> until the transaction completes, preferably with a delay between calls to allow time for data to transfer.</p>

<p>The BSC master peripherals support a variety of status information. The transfer active condition indicates when a transfer is in process and is presented by the <code>i2c_pins::is_busy</code> member function which returns <code>true</code> while data transfer is ongoing. For finer grained control there are various FIFO states that can be queried.</p>

<p>There are a couple of potential communication errors. A slave device may fail to acknowledge an address and the SCL clock line may timeout. Slaves can stretch clock ticks on SCL within limits â€“ set as one of those communications parameters passed to <code>i2c_pins</code> constructors. A slave does this if it cannot respond quickly enough and needs to slow the masterâ€™s outpourings. The error states can be queried with the <code>no_acknowledge</code> and <code>clock_timeout</code> member functions. Plagiarising the C++ standard library IOStreams states I also provided a <code>good</code> state query member function along with two state <code>clear</code> member functions â€“ one clearing both error states, the other clearing specific error states.</p>

<p>Listing 2 shows an example of using <code>i2c_pins</code> to write data to a memory device <a href="#[11]">[11]</a>, read the values back and display the written and read values and whether they differ. The memory deviceâ€™s write operation starts with the initial address to write to. The device has a 512 byte capacity, a 9-bit range, but the initial address is only 8-bits. The device uses two 256 byte pages to access the whole 512 bytes with page 0 having an even slave address and page 1 the following odd address. The first byte of the transferred data is written to the specified address with following bytes written to subsequent addresses. As the device read operation used does not specify a start address it is handy that addresses wrap round to zero after reaching 511. Reads start at the current address and then from each following address. So writing 512 bytes will return the current address to the initial location â€“ address zero in this case, which if followed by a read will read the previously written data starting with the first byte written.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
#include &quot;i2c_pins.h&quot;
#include &lt;array&gt;
#include &lt;thread&gt;
#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;iomanip&gt;

using namespace dibase::rpi::peripherals;

constexpr int wrap_length{512}; // bytes
constexpr unsigned char memdev_addrs{0x50}; 
  // page 0
typedef std::array&lt;unsigned char,wrap_length&gt;
  buffer_t;
void quick_doze()
{
  std::this_thread::sleep_for
  (std::chrono::microseconds{100});
}
void write(i2c_pins &amp; bsc,unsigned char dev_addrs
          , unsigned char start_addrs
          , buffer_t &amp; data)
{
  bsc.start_write(dev_addrs,data.size()+1
                 , &amp;start_addrs,1);
  unsigned char * write_ptr{&amp;data[0]};
  std::size_t remaining{data.size()};
  while (remaining)
  {
    if (bsc.write_fifo_has_space())
    {
      std::size_t transferred 
        = bsc.write(write_ptr, remaining);
      remaining -= transferred;
      write_ptr += transferred;
    }
   else
    quick_doze();
  }
  while (bsc.is_busy())
    quick_doze();
}
void read(i2c_pins &amp; bsc
        ,unsigned char dev_addrs,buffer_t &amp; data)
{
  bsc.start_read(dev_addrs,data.size());
  unsigned char * read_ptr{&amp;data[0]}; 
  std::size_t remaining{data.size()};
  while (remaining)
  {
    if (bsc.read_fifo_has_data())
    {
      std::size_t transferred 
        = bsc.read(read_ptr, remaining);
      remaining -= transferred;
      read_ptr += transferred;
    }
    else
      quick_doze();
  }
  while (bsc.is_busy())
    quick_doze();
}

int main()
{
  try
  {
    i2c_pins bsc1{pin_id{2},pin_id{3}};
    buffer_t wb;
    for (int v=0; v!=wrap_length; ++v)
      wb[v] = v;
    write(bsc1,memdev_addrs, 0,wb); 
    buffer_t rb = {{}};
    read(bsc1,memdev_addrs, rb);
    std::cout &lt;&lt; std::boolalpha 
              &lt;&lt; std::setfill('0')
              &lt;&lt; std::hex 
              &lt;&lt; &quot;Wrote Read Same?\n&quot;;
    for (int v=0; v!=wrap_length; ++v)
      std::cout &lt;&lt;   &quot;  &quot; &lt;&lt; std::setw(2) 
                &lt;&lt; int(wb[v])
                &lt;&lt; &quot;    &quot; &lt;&lt; std::setw(2) 
                &lt;&lt; int(rb[v])
                &lt;&lt;  &quot;   &quot; &lt;&lt; (rb[v]==wb[v])
                &lt;&lt; '\n';
  }
  catch (std::exception &amp; e)
  {
    std::cerr &lt;&lt; &quot;Failed because: &quot; 
              &lt;&lt; e.what() &lt;&lt; '\n';
  }
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<p>In <code>main</code> an <code>i2c_pins</code> instance is created using GPIO pins 2 and 3 for SDA and SCL respectively (see <code>pin_id</code> and friends <a href="#[12]">[12</a>, <a href="#[1]">1]</a>). This translates to using BSC1 â€“ hence the objectâ€™s name.</p>

<p>Using direct GPIO pin numbers in this case means knowing the Raspberry Pi revision as the original model B presents GPIO pins 0 and 1 on their P1 connectorâ€™s pins 3 and 5 â€“ which support BSC0, while later model B revisions and subsequent models (excepting the compute module) connect GPIO pins 2 and 3 to this pair of pins, supporting BSC1. The problem could be solved by specifying <code>p1_pin(3)</code> and <code>p1_pin(5)</code> or use the pre-defined objects <code>sda</code> and <code>scl</code>.</p>

<p>A <code>std::array</code> type, under the alias <code>buffer_t</code>, is used as the type for buffers. The write buffer is created and filled with values matching the index of each byte. The programâ€™s <code>write</code> function performs the write operation. It is passed the <code>bsc1 i2c_pins</code> object by reference along with the memory deviceâ€™s page 0 address, the memory address to start writing to and the write buffer by reference. The <code>write</code> function initiates a write transaction by calling <code>i2c_pins::write_start</code> on the passed <code>i2c_pins</code> object â€“ specifying the passed-in device address, one more than the write buffer length as the number of bytes to transfer to account for the initial memory page start address and passes the address of the memory page start address argument object as the single byte â€˜bufferâ€™ to initially transfer.</p>

<p>The following loop writes values from the write buffer to the FIFO. If there is space in the FIFO, determined by a call to <code>i2c_pins::write_fifo_has_space</code>, data is written to it from the write buffer otherwise the thread waits for space to become available by taking a short sleep â€“ as implemented by the <code>quick_doze</code> function. The loop terminates when all the data has been written to the FIFO but the transaction only completes shortly after the FIFO empties. We could call <code>i2c_pins::write_fifo_is_empty</code> but that â€˜completes shortly afterâ€™ can cause the peripheral to still be busy when the next transaction is attempted so it is best to wait for <code>i2c_pins::is_busy</code> to return <code>false</code>.</p>

<p>The values are then retrieved by calling the programâ€™s <code>read</code> function which takes the same parameters as <code>write</code> except there is no starting memory address value as the read operation used starts reading from the current memory address. A separate read buffer is passed to read so that both written and read values are available for comparison. The workings mirror those of <code>write</code>. The transaction is initiated by calling <code>i2c_pins::start_read</code> passing the memory deviceâ€™s address and the size of the passed data buffer to read into. Data is read into the buffer in chunks as they appear in the FIFO. Calls to <code>i2c_pins::read_fifo_has_data </code>check there is data to collect otherwise the thread takes a short doze. Finally <code>read</code> waits for <code>i2c_pins::is_busy</code> to return <code>false</code> indicating transaction completion.</p>

<p>The final action of <code>main</code> is to write out the bytes in the write and read buffers and whether each pair of values match.</p>

<p>You might be wondering why, as BSC masters do not have separate read and write FIFOs, why the FIFO checking member functions specify read and write in their names. The same conditions apply to <code>spi0_pins</code>, and SPI0 does have separate read and write FIFOs. Thinking some consistency might be nice I re-used the names.</p>

<h2>Iâ€™ve not finished so Iâ€™ll start</h2>

<p>The BSC masters support the I<sup>2</sup>C repeated start feature allowing a master and slave to conduct multiple transactions without asserting the stop condition and releasing the bus. Repeated start is only practically relevant to read operations where the master has to send some information to the slave device first â€“ a value identifying a device register to be read for example. In such cases the master sends the information on what is requested then enters a start condition, without first going through a stop condition, specifying the same slave address but changing the read/write bit to read.</p>

<p>To support repeated start read operations I added an overload of <code>i2c_pins::read</code> that takes the data to write as an additional <code>std::uint8_t</code> parameter. Repeated starts are normal (read) transactions issued before the preceding (write) transaction has completed. The documentation is not very clear but it seems repeated starts must be issued after the last byte has started transfer but not completed which is difficult if not impossible to detect for multi-byte transactions. So the initially written data is restricted to a single byte allowing the start of the last and only byteâ€™s transfer to be detected by waiting briefly and busily for <code>i2c_pins::is_busy</code> to return <code>true</code>. When it does the repeated start can be initiated â€“ but has to be setup in the short time before the write transfer completes. The <code>i2c_pins::read </code>overload only returns after the byte-write has completed, counter-intuitively by waiting for <code>i2c_pins::read_fifo_has_data</code> to return <code>false</code>, otherwise the byte transfer may be incompletely and falsely reported as read data.</p>

<p>Because the code runs on a pre-emptively scheduled system there is a chance the processor wanders off to do something else while waiting for the single byte write transaction to start and the whole transaction could have completed by the time the thread is scheduled to run again. This means the window in which <code>i2c_pins::is_busy</code> returns <code>tru</code> is missed and the wait loop will never exit. To prevent this a maximum number of iterations is defined and an iteration count kept. If the count exceeds the maximum, <code>false</code> is returned immediately indicating a missed repeated start and the caller should retry. Other error conditions are signalled by throwing an exception.</p>

<p>Listing 3 shows a <code>read</code> function that uses repeated starts with a random read operation of the memory device. It differs from the <code>read</code> function in listing 2 by having an additional <code>mem_addrs</code> parameter which is passed to the repeated-start supporting <code>i2c_pins::start_read</code> member function in a loop which permits a number of retries to account for the possibility of failure due to context-switches as discussed above.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
bool read(i2c_pins &amp; bsc,std::uint8_t dev_addrs
         ,std::uint8_t mem_addrs, buffer_t &amp; data)
{
  int remaining_tries{3};
  bool started{false};
  while (!started)
  {
    started = bsc.start_read(dev_addrs
                         ,mem_addrs,data.size());
    if (!started &amp;&amp; --remaining_tries==0)
      return false;
  }
  std::uint8_t * read_ptr{&amp;data[0]}; 
  std::uint32_t remaining{data.size()};
  while (remaining)
  {
    if (bsc.read_fifo_has_data())
      {
        std::uint32_t transferred 
          = bsc.read(read_ptr, remaining);
        remaining -= transferred;
        read_ptr += transferred;
      }
     else
      quick_doze();
  }
  while (bsc.is_busy())
    quick_doze();
  return true;
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>

<h2>The ten-bit cunning scheme</h2>

<p>One use of repeated starts is to support I<sup>2</sup>C 10-bit addressing. The additional address bits are provided by a byte written before the rest of the transaction, which for write transactions just adds an additional byte to the transaction similar to the listing 2 <code>write</code> function. Read transactions from 10-bit addressed slave devices require the extra address byte to be written followed by a repeated read-transaction start as per the listing 3 <code>read</code> function. You would think the extra 8-bits would give a 15 bit address but the upper 5 bits of the usual 7-bit part of the address use a fixed pattern specifying a reserved range of addresses, leaving only the lower 2 bits to be available for use as the most significant bits of the extended 10 bit address.</p>

<h2>Wrapping up</h2>

<p>So thatâ€™s about it. I think C++, and C++11, features proved useful in providing simple interfaces to GPIO and other peripherals. The resultant overall structure of the library appears to allow easily adding support for other peripherals or even other modes of peripherals having existing support â€“ such as the serialiser mode of the PWM controller.</p>

<p>There are some parts that have not worked out quite as well as they could. The pin and peripheral allocation support is I think the part with the most problems. While tracking which pins and peripherals are in use is a good thing in theory as there is no system wide way of achieving this the partial solutions currently implemented by the library leave quite a lot to be desired.</p>

<p>While developing the initial implementation I intentionally ignored concurrency and synchronisation issues. While the library can with care be used in a multithreaded environment there should be a review of concurrency concerns at the very least â€“ especially as the latest Raspberry Pi 2 model B has a 4 core chip.</p>

<p>Which leads on to supporting the growing list of Raspberry Pi models. The main concern is that the new BCM2836 based Raspberry Pi 2 model B maps peripheral registers to a different base address. Other concerns are supporting the additional GPIO pins on the larger 40 pin connector and detecting which model code is running on. I have added some preliminary support for these things to the <code>pin_id</code> family of classes and for use by the <code>rpi_info</code> type to determine the board revision details.</p>

<p>But before rushing into too much new functionality it is probably a good point to review the interfaces provided for each peripheral as well as the code in general and of course those 2-wire modes of <code>spi0_pins</code> still need to be tested.</p>

<h2>References</h2>

<p class="bibliomixed"><a id="[1]"></a>[1]	Raspberry Pi Linux User Mode GPIO in C++ (Part 1), <em>CVu</em>, Volume 27 Issue 2, May 2015</p>

<p class="bibliomixed"><a id="[2]"></a>[2]	Raspberry Pi Linux User Mode GPIO in C++ (Part 2), <em>CVu</em>, Volume 27 Issue 4, September 2015</p>

<p class="bibliomixed"><a id="[3]"></a>[3]	dibase-rpi-peripherals library project:<a href="https://github.com/ralph-mcardell/dibase-rpi-peripherals">https://github.com/ralph-mcardell/dibase-rpi-peripherals</a></p>

<p class="bibliomixed"><a id="[4]"></a>[4]	Resource acquisition is initialization (RAII), see for example:<a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization</a></p>

<p class="bibliomixed"><a id="[5]"></a>[5]	Gertboard Raspberry Pi IO expansion board:<a href="http://www.raspberrypi.org/archives/411">http://www.raspberrypi.org/archives/411</a></p>

<p class="bibliomixed"><a id="[6]"></a>[6]	Serial peripheral interface (SPI), see for example:<a href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus">https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus</a></p>

<p class="bibliomixed"><a id="[7]"></a>[7]	BCM2835 ARM Peripherals: <a href="http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf">http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf</a></p>

<p class="bibliomixed"><a id="[8]"></a>[8]	Master/slave model, see for example:<a href="https://en.wikipedia.org/wiki/Master/slave_(technology)">https://en.wikipedia.org/wiki/Master/slave_(technology)</a></p>

<p class="bibliomixed"><a id="[9]"></a>[9]	ATmega48A/PA/88A/PA/168A/PA/328/P 8-bit microcontroller datasheet: <a href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a></p>

<p class="bibliomixed"><a id="[10]"></a>[10]	Inter-Integrated Circuit (I<sup>2</sup>C):<a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">http://www.nxp.com/documents/user_manual/UM10204.pdf</a></p>

<p class="bibliomixed"><a id="[11]"></a>[11]	Cypress FM24CL04B 4-Kbit (512 x 8) Serial (I<sup>2</sup>C) F-RAM<a href="http://www.cypress.com/file/136466/download">http://www.cypress.com/file/136466/download</a></p>

<p class="bibliomixed"><a id="[12]"></a>[12]	The <code>pin_id</code> class et al in <span class="filename">pin_id.h</span>: <a href="https://github.com/ralph-mcardell/dibase-rpi-peripherals/blob/master/include/pin_id.h">https://github.com/ralph-mcardell/dibase-rpi-peripherals/blob/master/include/pin_id.h</a></p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
