Atul Charate
Atul Charate

Reputation: 41

Bit banging for SPI in ARM

I am trying to read the data from FXLS8471Q 3-Axis, Linear Accelerometer using SPI. I am using bit banging method to read the data from Accelerometer. I am using LPC 2184 ARM processor. I used the following code.

unsigned char spiReadReg (const unsigned char regAddr)

{

  unsigned char SPICount;                               

  unsigned char SPIData;                  

  SPI_CS = 1;                                           
  SPI_CK = 0;                                           
  SPIData = regAddr;                                    

  SPI_CS = 0;                                           
  for (SPICount = 0; SPICount < 8; SPICount++)          
  {
      if (SPIData & 0x80)
         SPI_MOSI = 1;
      else
         SPI_MOSI = 0;
      SPI_CK = 1;
      SPI_CK = 0;
      SPIData <<= 1;
  }                                                     
  SPI_MOSI = 0;                                         

  SPIData = 0;
  for (SPICount = 0; SPICount < 8; SPICount++)          
  {
     SPIData <<=1;                                       
     SPI_CK = 1;                                         
     SPIData += SPI_MISO;                                
     SPI_CK = 0;         
     SPIData &=(0xFE);
  }                                                     
   SPI_CS = 1;                                           

  return ((unsigned char)SPIData);                      
}

But instead of getting valid value 0x6A , I am getting garbage value. Please help me out to solve this problem;

Upvotes: 1

Views: 2039

Answers (3)

user3629249
user3629249

Reputation: 16540

be sure to compile your function with NO optimization as that will corrupt the bitbang operation.

this is the code from the maxum site for the spiReadReg function. (which looks like were you got your code.

However, this is just a guide for the 'general' sequence of operations for communicating with the maxim 1481 part.

the accel. part needs several setup commands and reads completely differently

Suggest reading the app notes and white papers available at freescale.com for the specific part number.

Those app notes/white papers will indicate the sequence of commands needed for setting up a specific mode of operation and how to request/interpret the resulting data.

There are a number of device specifics that your code has not taken into account.

Per the spec sheet the first bit transmitted is a read/write indicator, followed by 8 bits of register address, followed by 7 trash bits (suggest sending all 0's for the trash bits.) followed by the data bits.

Depending on the setup commands, those data bits could be 8 bits or 14 bits or multiple registers of 8 or 14 bits per register.

Upvotes: 0

vsz
vsz

Reputation: 4893

SPIData &=(0xFE); as pointed out in another answer, is definitely wrong as it erases the bit you just received.

However, there are other major issues with your code. An SPI slave device sends you data by setting the value of MISO on a rising or falling clock, depending on the type of device. However, you didn't wait in your code for the value to appear on MISO.

You control the communication by setting the clock to 1 and 0. The datasheet of the accelerometer says on page 19, that

Data is sampled during the rising edge of SCLK and set up during the falling edge of SCLK.

This means that in order to read from it, your processor needs to change the clock from one to zero, thereby signaling the accelerometer to send the next bit to the MISO. This means you did the reverse, you in your code read on a rising edge while you should be reading on the falling edge. After setting the clock to zero, you have to wait a little while until the value appears on MISO, and only then should you read it and add it to your SPIData variable. Table 9, SPI timing indicates how much you have to wait: at least 500 nanoseconds. That's not much, but if your CPU runs faster than 2 MHz then if you don't use a delay, you will try to read the MISO before the accelerometer had time to properly set it.

You also forgot the slave Select, which is actually required to indicate the beginning and the end of a datagram.

Check the Figure 7. SPI Timing Diagram in the datasheet, it indicates what you are required to do and in what order, to communicate with the device using SPI.

I also suggest reading about how the rotating registers of the SPI work, because it seems from its datasheet, that the accelerometer needs to receive a well specified number of bits before useful data appears on its output. Don't forget, as you send a single bit to the device, it also has to send a bit back to you, so if it didn't decode a command yet, it can only send gibberish. Your code, as the master, can only "push" bits in, and collect the bits which "pop out" on the other side. This means you have to send a command, and then send further bits until all the answer is pushed out to you bit by bit.

If you get stuck, I think you will have much more luck getting help on https://electronics.stackexchange.com/, but instead of just putting this same code there (which seems to be blindly copied from www.maximintegrated.com and has absolutely nothing to do with the problem you try to solve), I strongly recommend trying to understand the "Figure 7. SPI Timing Diagram" I was suggesting before, and alter your code accordingly. Without understanding how the device you try to communicate with works, you will never succeed if you just blindly copy the code from a completely different project just because it says "spi" in the title.

Upvotes: 3

Siddhartha Ghosh
Siddhartha Ghosh

Reputation: 3198

SPIData &=(0xFE);

The above line is causing the problem. Here the LSB is reset to 0 (which contained the data bit just taken from MISO) -- basically you are destroying the bit you just read. Omitting the line should correct the problem.

Upvotes: 0

Related Questions