It all started with a support request from a Pi-Plate owner: he kept getting a message that the DAQC wasn't being found when he imported the Python library. So, we asked him to check his power supply and then to verify that the board was seated properly. None of those things worked so we suggested he reinstall the library and that didn't work either. He was getting ready to try another Raspberry Pi 2 when it occurred to us to ask if he was overclocking. He said he was but only by a modest amount.

Hearing that, we decided to investigate further. First, we launched raspi-config and looked at the overclock options:

Capture

The customer was using the Pi2 overclock option which ramped his ARM processor speed from 900 to 1000MHz. But it also doubles the core clock from 250 to 500Mhz. At this point we still didn't know what the exact problem was so we selected the Pi2 overclock option and rebooted the RPi. Emulating the customer, we wrote a quick and dirty script called dirty.py that looks like:

Using an SSH shell, we ran the above script and got the following:

Capture

Aha! Now we were able to reproduce the problem. When the DAQC module is imported, a small piece of code runs to determine if any boards are attached. This code goes out and scans all of the eight possible addresses for a DAQC to detect if one is present. If none are found then the above message appears. Knowing this, the next step was to look at the SPI signals with a logic analyzer and see what's happening when the module is imported. Here's what the scan looks like on the logic analyzer:

Capture

The above shows eight poll instructions and eight replies. That -looks- correct but let's zoom in a little bit:

Capture

It might be a little hard to see but the SPI clock frequency is approximately 1Mhz. This is twice as fast as what the RPi normally operates and is also too fast for the microprocessor on the Pi-Plate to buffer and parse. So, we contacted the customer and told him to stop overclocking while we investigated further.

The Raspberry Pi 2 is based on a Broadcom BCM2836 Arm7 Quad Core Processor. Out of the box, the ARM clock operates at 900Mhz and the GPU core clock runs at 250Mhz.  Some research found that the SPI clock (SCLK) is set by a register in the BCM2836 called CDIV with the output frequency being: SCLK = coreCLK/CDIV. Furthermore, CDIV has to be a power of 2 such as 4, 8 16...256, 256, 1024, etc. (Note: this is how it is implemented in the driver. There is some evidence indicating that there is a typo in the documentation and that CDIV can be a multiple of two.) When overclocked, coreCLK is set to 500Mhz and we measured an SCLK of about 1Mhz which means that CDIV must be about 500 or, since it has to be a power of two: 512. So, to fix the problem, we'll just read the core clock value and set CDIV manually. That's all, right? Wrong.

To access SPI functions through Python it is necessary to go through some wrapper functions which then call functions in SPIDEV which then call a general purpose Linux driver called  IOCTL which then calls a BCM2836 specific routine that talks to the SPI hardware. Follow all that? Here it is shown as a diagram:

spi.writebytes(arg) -> SpiDev_writebytes(args) -> ioctl(args) -> bcm2708_spi_transfer(args)

Embedded in those arguments being passed to each function are pointers to structures containing a number of settings for the SPI interface such a mode, number of bits, and the clock rate. So, one does not simply write to the CDIV register to set SCLK. Instead, it is necessary to pass a desired clock rate to SPIDEV with the following statement: spi.max_speed_hz = 500000. SPIDEV then takes this value, saves it into a structure and then passes the information along to the Linux driver with every call. The CDIV value is calculated in a setup routine in the spi-bcm2708.c module using the following code:

The coreCLK is read into a variable called bus_hz and the desired value of SCLK is passed in a variable called hz. After a few limit checks, CDIV is calculated first calculating and rounding up the ratio of coreCLK/SCLK. Then it is rounded up to the nearest power of 2. For example, if we request a SPI clock of 500,000 and the core clock is 250Mhz then we get the following:

DIV_ROUND_UP(250,000,000, 500,000) = 500 (DIV_ROUND_UP is a c macro: #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)))

roundup_pow_of_two(500) = 512 (roundup_pow_of_two is another macro: 1UL << (ilog2((n) - 1) + 1))

So with core CLK at 250Mhz, a requested SCLK value of 500Khz results in a CDIV value of 512 with translates to a SPI clock of 250Mhz/512=488,281.25Hz.

Assuming that there was a default value we had to override, it seemed like the easiest fix was to place the max_speed_hz statement right after we opened the SPI port in our library. After updating the library we ran dummy.py again and got:

Capture

Well, that was unexpected. Turning to our logic analyzer again we found that the clock was still running at just under 1Mhz (500Mhz/512=976,562.5 to be precise). Does this mean that instead of using the true value of the core clock value of 500Mhz, the driver is using a constant of 250Mhz? Our next step was to be clever and fool the driver by asking for a maximum SPI clock of 250Khz. Our results were...weirdly inconsistent. Case in point: besides polling for available DAQC plates when loaded, the library will also read the 5VDC voltage and initialize the PWMs for each board found. For reading the voltage, the protocol is to send a four byte command and then read back two bytes. Here is what DAQC.getADC(0,8) looked on the logic analyzer after requesting a max bus speed of 250Khz:

Overclocking Images

At the top of this image we can see the complete sequence of the getADC command with the four byte instruction being sent to the DAQC followed by the 2 A/D bytes being returned. Zooming in on the command section on the lower left, the logic analyzer indicates that the SPI clock is running at 484.8Khz. But, zooming in on the clock for the data fetch on the lower right indicates that the SPI clock is now operating at 941Khz. While we're not concerned about the absolute values, we are concerned about the 2X clock speed change that occurred in a span of 250 microseconds.

So, what's the fix? We had hoped to end this blog entry with a link to a patch or an update that would allow you to overclock your core while continuing to use your DAQCplate. But with the inconsistent behavior of the RPi SPI driver, this is the only thing we can recommend if you want to overclock your Pi2:

  1. Using raspi-config,  choose the Pi2 overclock option and reboot
  2. From the Linux command prompt type cd /boot and hit <ENTER>
  3. Next, type sudo nano config.txt and hit <ENTER>
  4. Using the down arrow key, scroll all the way to the bottom of the file and locate the line that says "core_freq=500"
  5. Change the value to 250 so it says "core_freq=250"
  6. Press <CNTL-O> to save and <CNTL-X> to exit the nano editor.
  7. Finally, type sudo reboot and hit <ENTER>

You are now overclocking your ARM processor and SDRAM while leaving the core clock at its original speed. It is our hope that this issue will eventually be addressed by the folks at the Raspberry Pi Foundation. When that happens we will post an update. Until then, here's a shout out to the guys at MachinaBio for working with us on this problem!

Series Navigation<< The Problem(s) with NeopixelsNice Video of Last Summer's KC Maker Faire >>
14 Comments
  1. Hi
    I'm having the same problem with my DAQC plate, so i followed your suggestion...but always getting "No DAQCplates" found.
    I also tries with Overclock = None, but the same result.
    Green light on the DAQC plate is on, 3.3 and 5V supply checks ok using a multimeter.

    Hardware is Raspberry Pi 2 Model B v1.1

    Any suggestions appreciated.

    • Les,

      Did the DAQC work before you changed the clock speed?

      • No, the DAQC is new and has never worked. Not sure if it is a defective board or clock timing issue. I've tried Overclocking = None, and also the suggestion to set the Core Speed = 250.

        • Two Suggestions:
          1) Reprogram your SD card with Raspian and see if it works after that
          2) If #1 doesn't work, try using a different RPi.
          3) If #2 doesn't work, let me know and we'll get you taken care of.

          • Thanks for the suggestion, I'll let you know the result.
            A couple of questions/observations after doing some debugging today
            (1) In the code DAQCplate.py, I notice there is a variable GPIObaseADDR = 8. Why are you offsetting the address by 8? I don't see any reference to this in the help.

            (2) I ran the python debugger and stepped thru the code to see what was going on. In the function ppCMD(), I was able to verify that:
            (a) GPIO.output(ppFRAME,TRUE) sets the pin to 3.3V.
            (b) GPIO.output(ppFRAME.False) sets the pin to 0.0V

            So at least the RPi is responding to the commands.

          • The base Pi-plate address for the DAQC is 8 so the range of absolute addresses is 8-15. For the MOTORplate the base address is 16 so the absolute range is 16 - 23. I keep it simple for the user and just use address 0 through 7 for each board. this system allows me to stack different kinds of boards while using simple addressing.

          • My results
            (1) Reprogram SD card - DAQC board not found.
            (2) Tried another RPi B - DAQC board not found

            Tried reloading python software a few times on both computers, but still no luck. Any new suggestions would be appreciated.

          • Sounds like you got a defective board - I apologize and also appreciate your troubleshooting. I'll get a new out to you first thing on Monday

  2. Hey Les, one more question: do you have any other devices plugged in other than the DAQCplate?

    • Hi

      The DAQCplate is the only device plugged into the RPi. Also no analog inputs were connected to the DAQCplate yet.

  3. Hi

    Any plans to develop a 16 bit or 24 bit ADC plate?

    • For now, we're planning the following changes to the next generation DAQCplate:
      1) +/-10 volts input
      2) 12 bit resolution (1 MSB = 5mV)
      3) An oscilloscope mode where we sample and store 512 bytes of data at 50Khz.

      With that said, I'm curious what you need those extra bits for.

  4. My current project is a seismograph for measuring earthquakes, magnitude range 2 to 4. Waveforms with a wide range of amplitudes. Frequency band up to 100 hz. Sample rate 2ms. Probably needs a low noise, low pass filter preamp.

    • What do you plan to use as a sensor?

Comments are closed.