SPI Read and Write

Hi guys,

I am getting to grips with MBED and SPI and I seem to have difficulty in reading from slave device registers. I can write to them without issue and confirmed this with a picoscope. However, I get nothing when trying to read from it.

For a little back ground, I am using the DRV8711 stepper motor driver with a LPC1768. the driver uses a 16 bit format with the MSB as the r/w bit (set high to read), followed by a 3 bit address and the remaining 12 bits are instructional. The MISO line also uses a 2K pullup resistor.

Could some one please help me to understand where I could be going wrong and possibly give some advice regarding best practice when programming SPI?

int main(){
    initSPI();
    initDRV8711();
    wait_us(500000);

    while(1){
        readReg(0b111);     //read STATUS Reg, confirm using PicoScope                           
        wait_us(500000);
    };
}

void initSPI(){
    _cs = CS_DISABLE;
    DRV8711.format(16, 3);      //16 bits, mode 3 
    DRV8711.frequency(125000);  //125KHz
}

void writeReg(int address, int data){
    int setWrite = 0 << 3;                      //set the write bit and format it to represent w000
    int instruct = setWrite | address;          //OR the address with the write instruction, WAAA
    int formattedInstruct = address << 12;      //format the instruct into a 16 bit word, WAAA 0000 0000 0000
    int command = formattedInstruct | data;     //OR the formatted instruction with the data to be sent, WAAA DDDD DDDD DDDD

    _cs.write(CS_ENABLE);
    wait_ns(6);

    DRV8711.write(command);  //send command
    wait_ns(6);

    _cs.write(CS_DISABLE);
}

int readReg(int address){
    int setRead = 1 << 3;                              //set the read bit and format it to represent w000
    int instruct = setRead | address;                  //OR the address with the write instruction, WAAA
    int formattedInstruct = address << 12;              //format the instruct into a 16 bit word, WAAA 0000 0000 0000
    int command = formattedInstruct | 0b000000000000;   //OR the formatted instruction with the data to be sent, WAAA DDDD DDDD DDDD

    _cs.write(CS_ENABLE);
    wait_ns(6);

    int value = DRV8711.write(command);  //send dummy command
    wait_ns(6);

    _cs.write(CS_DISABLE);

    return value;
}

Thank you in advance for your help!

Hello Andrew,

I think you should rather shift the instruct variable than the address one when defining the formattedInstruct as below:

//int formattedInstruct = address << 12; 
int formattedInstruct = instruct << 12; 

Your code works for writing to registers because the read/write bit should be set to 0. But it doesn’t in case of reading because it should be set to 1, however it is set to 0.
I believe your original plan was to use it that way (as you wrote in the comment). This type of bug often happens to me too and it is difficult to find. You need another person to spot it :slight_smile:

2 Likes

Hi Zoltan,

Thank you for reply.

To read from the device registers, I’ve implemented a seperate function int readReg(int address) which sets the read bit high before sending the command which is a ‘dummy’ command since in this case only the first four bit are needed. (Ive added a screen shot of the data sheet below for clarity). Apologies if i wasn’t clear about the read/write being seperatefunctions, ill make a note in the original post.

Thanks,

Andrew

To read from the device registers, I’ve implemented a seperate function int readReg(int address) which sets the read bit high before sending the command …

I have seen the readReg function. But, as I said in my first post, it does not set the read bit high!

int readReg(int address){
    int setRead = 1 << 3;                              //set the read bit and format it to represent w000
    int instruct = setRead | address;                  //OR the address with the write instruction, WAAA

//============================================================================
// Please have a closer look. The bug is below!
//
// At this point: 
// address = 0AAA and instruct = 1AAA
    int formattedInstruct = address << 12;  //formats the address into a 16 bit word, 0AAA 0000 0000 0000
// Because the address variable was used in the expression above, 
// after the assignment the read bit (most significant bit) is set to 0.
// At this point: 
// formattedInstruct = 0AAA 0000 0000 0000

//============================================================================
// Fixed code.
// 
// At this point: 
// address = 0AAA and instruct = 1AAA
    int formattedInstruct = instruct << 12;  //formats the instruct into a 16 bit word, 1AAA 0000 0000 0000
// Because the instruct variable was used in the expression above (rather
// than address), after the assignment the read bit (most significant bit)
//  is set to 1.
// At this point: 
// formattedInstruct = 1AAA 0000 0000 0000
//============================================================================

    int command = formattedInstruct | 0b000000000000;   //OR the formatted instruction with the data to be sent, WAAA DDDD DDDD DDDD

    _cs.write(CS_ENABLE);
    wait_ns(6);

    int value = DRV8711.write(command);  //send dummy command
    wait_ns(6);

    _cs.write(CS_DISABLE);

    return value;
}

I hope this helps,

Zoltan