Jump to content

SPI with 16 bit data

Recommended Posts

Hi,  I am new to coding and I am having trouble setting wipers on a digital pot.  The pot I am using (MCP4231) requires a 16 bit instruction to set the wiper position.  The reference sheet indicates that chip select stays low for 16 clock cycles.  Using the library posted by Reaper7 and Rei Vilo (big thanks, by the way), I was able to transfer 2 x 8 bit bytes, but that did not reset the wipers.  (I have access to an oscilloscope, so I can see what is going on). Figuring that the problem was that the chip select goes high between the two transfers, I put the following into my SPI library:   


            uint8_t SPIClass::trans2ByteA(uint8_t data) {

                  return transfer(slaveSelect, data, SPI_CONTINUE); }

            uint8_t SPIClass::trans2ByteB(uint8_t data) {

                  return transfer(slaveSelect, data, SPI_LAST); }


While these new commands gave me a way to send two 8 bit bytes, the wipers stayed at mid position.


It does not look as if the problem arises from me sending the wrong command byte; I wrote a sketch that cycled through all 256 possible values and output a voltage to an analog read pin that should have been sensitive to the wiper position.  Values from the analog read output to a serial file did not change over the course of the experiment.


Assuming that the problem had something to do with the odd delay between the two bytes, I have been trying to figure out a way to transfer a uint16_t data byte.  Setting the last argument in the following piece from SPI library to 16 gave me 16 clock ticks on the SCK:

   int SPIClass::bits(int dataBits) { ..etc...

Unfortunately, I have been unable to figure out how to send a 16 bit byte from MOSI.  The following Energia code only sends the last 8 bits:


    unsigned int address0 = command0 << 8;
      uint16_t wiper0 = address0 | level;


the trans16 command has the following code in the library:

    uint16_t SPIClass::trans16(uint16_t data16) {

    return transfer(slaveSelect, data16, SPI_LAST); }


My guess is that it has something to do with how "transfer" is defined.

Any help or advice would be appreciated.





Link to post
Share on other sites

Problem solved.  This was a hardware issue.  I guess I cooked the digital pot while trying to solder it to the board.  Replacing the pot resulted in behavior predicted for my test circuit.   In case anyone is interested, I have pasted the energia code I tested the pot with below.  The circuit is described as well.  The sketch uses the trans2byte commands described above and the SPI library from Reaper7 and Rei Vilo. 

Sorry for the confusion.



  Sketch for testing MCP 4231 digital potentiostat with volatile memory.
  modified from the Digital Pot Control example that comes with Energia
    Originally by Tom Igoe, Rick Kimball, Heather Dewey-Hagborg, 2005 to 12
    Spi module 0 requires SPI library from Reaper7.
  The circuit:
 CS, SCK, and SDI attached to respective module zero pins (CS(0), SCK(0), MISO(0)}
  Pin P0A connected to VCC,
  Pins P0W, P0B, P1W and P1A all connected,
  Pin P1B connected to A11 with a 10 Kohm resister between A11 and GND.
  This gives:
    VCC-R1-(R2, analogRead)-R3 (10Kohm)-GND
    by cycling values to the two pots, values of R1 and R2 can be changed.
    Values of R1 and R2 can be determined from serial output of analog signal.
   * MOSI - to J1 pin 8
  * CLK - to J2 pin 11 (SCK pin) P1.5
#include<Energia.h>  // required to get spi to work.
#include <SPI.h>  // include the SPI library from Stellarisiti
#include "wiring_analog.c"

   int gain0;
   int gain1;
   unsigned int address1 = 16;
   unsigned int address0 = 0;
#define Iread_pin  A11              //J1 pin 2, Analog read current, was A3  

unsigned int iRead = 0;                 // hight pulse current read
void setup() {

  pinMode (Iread_pin,INPUT);

  Serial.begin(9600);             // begin serial comm. at 9600 baud
///////// header //////
Serial.print("gain 0");    
Serial.print("gain 1");

void loop() {
 ///////// ramp up R0 holding R1 constant ////////
  for (int m=0; m<128; ++m) {
   gain1 = m;
      digitalPotWrite(16,gain1);  //write to channel 1
      digitalPotWrite(0,gain0);    // write to channel 0
  for (int n=0; n<128; ++n) {
    gain0 = n;
    gain1 = 64;
       digitalPotWrite(address1,gain1);  //write to channel 1
      digitalPotWrite(address0,gain0);    // write to channel 0

int digitalPotWrite(int address, int value) {


void readVolts() {
   unsigned int iRead = 0;               
           for (int i =0; i<=15; ++i){  
         iRead += analogRead(Iread_pin);}
         int mVi = (iRead)/16;
         mVi = mVi*3558/4098;          // digital reading converted to mV


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...