title: How to correctly receive data through SPI enhanced buffer mode of Microchip PIC24F microcontrollers?
body: <p>I'm programming a SPI communication with an external RF chip. The microcontroller is the model PIC24FJ64GA102 from Microchip.</p>
  
  <p>I want to use the <strong>enhanced buffer mode</strong> of the SPI.</p>
  
  <p>Problem: Get the received bytes out of the receive buffer.</p>
  
  <p>Used SPI function:</p>
  
  <pre><code>void SPI1_get(uint8_t* data, uint16_t length) {
      uint16_t i = 0, l = length;
      uint8_t dummy;
      while (length &gt; 0) {
          while (SPI1STATbits.SPITBF || SPI1STATbits.SPIRBF) {
              dummy = SPI1STAT;
          }
          do {
              SPI1BUF = 0xff;
          } while (SPI1STATbits.SPIRBF == 0 &amp;&amp; --length &gt; 0);
          do {
              while (SPI1STATbits.SRMPT == 0) {
              }
              data[i] = SPI1BUF;
              ++i;
          } while (i &lt; l &amp;&amp; SPI1STATbits.SRXMPT != 1);
      }
  }
  </code></pre>
  
  <p>Here the calls:</p>
  
  <pre><code>uint8_t cmd[2]; cmd[0] = length; cmd[1] = address;
  SPI1_put(cmd,2); // e.g: 0x02, 0x01
  SPI1_get(buf,2); // e.g: 0x05, 0x01 (received data)
  </code></pre>
  
  <p>The communication is just fine, checked with an oscilloscope and SPI decoding module. The data on the SPI bus are like in the comment above: sent <code>0x02 0x01 0xff 0xff</code>, received <code>0x00 0x00 0x05 0x01</code>, but the function above does not correctly retrieve the data out of the receive buffer. I've already tested a lot of constellations of checking flags and interrupts but in the end the best result I can get is: <code>0x00 0x01</code> (only the last byte is correct).</p>
  
  <p>Also already checked the errata sheet, where two SPI problems are mentioned which do not (should not) affect my code.</p>
  
  <p>What the hell am I doing wrong?!</p>
  
  <p>As requested here the SPI1_put() function:</p>
  
  <pre><code>void SPI1_put(uint8_t* data, uint16_t length) {
      uint16_t i = 0;
      uint8_t dummy;
      for (; i &lt; length; ++i) {
          while (SPI1STATbits.SPITBF)
              ; // maybe change to (_SPI1BEC == 7) ?
          SPI1BUF = data[i];
          dummy = SPI1BUF; //dummy read
      }
  }
  </code></pre>
  
  <p><strong>[latest edit: 2015-02-05]</strong></p>
  
  <p>So today I was able to spend some more time on this particular issue, and came up with a port of ElderBug's suggestion, also taking care of the bugs mentioned in the errata sheet:</p>
  
  <pre><code>uint8_t out_buf[128];
  uint8_t in_buf[128];
  
  void SPI1_com(uint8_t* out, uint8_t* in, uint16_t out_len, uint16_t in_len) {
      uint16_t len = out_len + in_len;
      uint16_t sent = 0, recv = 0, i = 0;
  //  while (!SPI1STATbits.SRXMPT)
      sent = SPI1BUF; // empty buffer
      sent = SPI1BUF; // empty buffer
      sent = 0;
      if (out != out_buf &amp;&amp; out != 0)
          memcpy(out_buf, out, out_len);
      while (sent &lt; len &amp;&amp; recv &lt; len) {
          if (SPI1STATbits.SPIBEC != 7 &amp;&amp; sent &lt; len) {
              SPI1BUF = out_buf[sent++];
          }
          if (!SPI1STATbits.SRXMPT &amp;&amp; recv &lt; len) {
              in_buf[recv] = SPI1BUF, recv++;
          }
      }
      if (in != 0) {
          for (i = 0; i &lt; in_len; ++i) {
              in[i] = in_buf[out_len + i];
          }
  //      memcpy(in, in_buf + out_len, in_len);
      }
      for (i = 0; i &lt; len; ++i) {
          out_buf[i] = 0xff;
          in_buf[i] = 0xff;
      }
  }
  </code></pre>
  
  <p>This code basically works. With an exception which I was not able to work around: </p>
  
  <p>The communication works as follows:</p>
  
  <ul>
  <li>1byte: r/w-bit+length</li>
  <li>1byte: address</li>
  <li>1-127byte: data</li>
  </ul>
  
  <p>So, when I read 1 byte from the slave chip, meaning sending 3 bytes (rw+len, address, dummybyte), the data I have in my <code>in_buf</code> buffer is 0xFF.
  Now a weird thing: When I just read one more byte, without changing anything (just one more dummy byte on the bus), the 1st byte of my <code>in_buf</code> has got the correct data. But this seems not to work always, because my program still stucks at some points.</p>
  
  <p>I'm left sitting here with a lot of question marks.</p>
  
  <p>Weird thing the 2nd: Reading 8 bytes, data correct in my buffer until the last byte, last byte is 0xFF, should be 0x00. Wtf?</p>
  
  <p>PS: Already filed a ticket at Microchip for support in this issue.</p>