PSoc 4-MPU9250 SPI Writing and Reading function

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hi guys,

   

Currently I am using PSoC 4200M as master to readout the motion sensor data (MPU9250, as slaver) via SCB SPI. I have basically finished the program, but it does not work. 

   

As I am very new for PSoC, I just like to confirm with your the correctness of the SPI writing and reading function. 

   

I have defined dedicated functions for registers Writing and Reading, as shown below.
/* Write Register*/
void MPU9250_WriteReg( uint8_t WriteAddr, uint8_t WriteData )
{
  SPIM_SpiUartWriteTxData(WriteAddr);
  SPIM_SpiUartWriteTxData(WriteData);
}

   

/* Read Register*/
uint8_t MPU9250_ReadReg( uint8_t ReadAddr )
{
  uint8_t ReadData = 0;
    
  SPIM_SpiUartWriteTxData(0x80 | ReadAddr);
  ReadData = SPIM_SpiUartReadRxData();
  return ReadData;
}

   

/* Read a series of  Registers*/
void MPU9250_ReadRegs( uint8_t ReadAddr, uint8_t *ReadBuf, uint8_t Bytes )
{
  uint8_t i =0;
  
  SPIM_SpiUartWriteTxData(0x80 | ReadAddr);  
  for(i = 0; i < Bytes; i++)
  ReadBuf = SPIM_SpiUartReadRxData()
}

   

But some websites said the Reading function need to add dummy bytes, and said the typical flow for the SPI master should be:
1) Send command byte(s)
2) Read and discard dummy byte(s) returned
Then to read back any response from the slave:
3) Send dummy byte(s)
4) Read response bytes(s) returned

   

Then, I updated the Reading functions correspondingly, as shown below:
/* Read Register updated*/
uint8_t MPU9250_ReadReg( uint8_t ReadAddr )
{
  uint8_t ReadData = 0;
  uint8_t dummy = 0;
    
  SPIM_SpiUartWriteTxData(0x80 | ReadAddr);
  dummy = SPIM_SpiUartReadRxData();
  SPIM_SpiUartWriteTxData(0xFF); // Dummy
  ReadData = SPIM_SpiUartReadRxData();
  return ReadData;
}

   

/* Read a series of  Registers updated*/
void MPU9250_ReadRegs( uint8_t ReadAddr, uint8_t *ReadBuf, uint8_t Bytes )
{
  uint8_t i =0;
  uint8_t dummy=0;
    
  for(i = 0; i < Bytes; i++) {
  SPIM_SpiUartWriteTxData(0x80 | ReadAddr + i);
  dummy = SPIM_SpiUartReadRxData();
  SPIM_SpiUartWriteTxData(0xFF); // Dummy
  ReadBuf = SPIM_SpiUartReadRxData();}  
}

   

If possible, could you help me check the correctness of both Writing and Reading function? Could you tell me which way is correct? Or even both ways are incorrect?

   

Many thanks for your help.

   

Kind Regards

   

Wesley

20 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Welcome in the forum, Wesley.

   

The second way is the correct way.

   

But

   

Before reading with SPIM_SpiUartReadRxData() you need to wait for the byte ready, the API will not wait.

   

When reading "a series" of bytes from successive locations you should move the SPIM_SpiUartWriteTxData(0x80 | ReadAddr + i); out of the loop. Most devices have got a data pointer which gets incremented.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi Bob, 

   

Thanks a lot for your warm welcome :). 

   

And many thanks for your reply, it is really helpful. If so, my writing function is right?

   

Sorry, would you mind tell me a bit of more details about how to implement the 'wait' function/'ready' flag for reading? 

   

Many thanks again.

   

Kind Regards

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Use SCB_SpiUartGetRxBufferSize() to check for the number of bytes received. When this is equal to the number of bytes sent you may continue with reading the results / dummies.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi Bob, thanks a lot for your reply. 

   

Sorry for bothering you again.

   

I have updated the code correspondingly below, but it still does not work... 

   

/* Read Register*/

   

uint8_t MPU9250_ReadReg( uint8_t ReadAddr )
{
  uint8_t ReadData = 0;
  uint8_t dummy = 0;
    
  SPIM_SpiUartWriteTxData(0x80 | ReadAddr); // Read Command and Address
  SPIM_SpiUartWriteTxData(0xFF); // Write Dummy 

   

  while (SPIM_SpiUartGetRxBufferSize() < 2) {} // Wait

   

  dummy = SPIM_SpiUartReadRxData(); // Read Dummy
  ReadData = SPIM_SpiUartReadRxData(); // Read Data
  return ReadData;
}

   

/* Read a seizes of Registers*/

   

void MPU9250_ReadRegs( uint8_t ReadAddr, uint8_t *ReadBuf, uint8_t Bytes )
{
  uint8_t i =0;
  uint8_t dummy=0;
  
   for(i = 0; i < Bytes; i++){
    SPIM_SpiUartClearRxBuffer();
    SPIM_SpiUartWriteTxData(0x80 | (ReadAddr+i)); // Read Command and Address
    SPIM_SpiUartWriteTxData(0xFF); // Write Dummy 
    
    while (SPIM_SpiUartGetRxBufferSize() < 2) {} // Wait
    
    dummy = SPIM_SpiUartReadRxData(); // Read Dummy
    ReadBuf = SPIM_SpiUartReadRxData(); // Read Data
    
    SPIM_SpiUartClearRxBuffer();}  // Reset buffer size to 0
}

   

I should misunderstand some points (particularly for the reading seizes of registers), could you give some feedbacks/advices?

   

Best Wishes

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Wouldn't bee too bad when you tell us what doesn't work. Did you use the debugger to see what runs?

   

Post your complete project, so that we all can have a look at all of your settings. To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob, 

   

 

   

Thanks a lor for your reply. 

   

 

   

Sorry, I didn't explain clearly. I used a logic analyzer to see the SPI signals. The SPI write is ok, but the SPI reading data is not correct, and the data is not changed with the motion sensor. I suppose maybe my MPU9250_ReadReg and MPU9250_ReadRegs are still wrong, then the data cna not be read properly? 

   

 

   

I attached my project file here. The SPI function is defined in the mpu6500.c file.

   

 

   

I also attached a screenshot of my logic analyzer. the channel 3 (MOSI) '187' is the read command & address, and the '255' is the write dummy, the channel 0 (MISO) '0' is the dummy reading and '219' is the data reading. '188' and subsequent registers are in the same flow. Here the readregs function is used. 

   

 

   

Could you feel free to have a look? Many thanks for your help.

   

 

   

Kind Regards

   

 

   

Wesley 

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Logic analyzer pictures look ok.

   

Your buffer for sprintf() is too small clobbering some ram data.

   

Set SPIM byte mode in advanced configuration.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi Bob,

   

Many thanks for your help, it is partially working! I got 4-axis data from the motion sensor via SPI. 

   

I think because limited by the size of the buffer, I can not readout the full 9-axis/6-axis data.

   

Do you know is there any other way to further increase the SPI buffer size?

   

Many thanks for your help.

   

I wish you Merry Christmas and Happy New Year ahead!

   

Best wishes

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

"I think because limited by the size of the buffer, I can not readout the full 9-axis/6-axis data." Your SPI buffer was set to 32 bytes size.

   

Your sprintf() buffer was too small.

   

And did you reset the index i in ReadBuf to zero again?

   

 

   

Season greetings

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob,

   

Many thanks for your reply. So if my understanding is correct, the only way is to increase the buffer size of SPIM? I found in the SCB datasheet(I attached below, SCB_P4_v3_20.pdf, in Page 98-99),  for PSoC 4200M the maximum RX/TX buffer size can only be 16 bytes. Then it seems no matter how larger the buffer size is set, the actual buffer size will be 16 bytes? If so, as you know, is there any other way to increase the SPIM buffer size?

   

ps, I used the MPU6500_ReadReg function (single register reading) to readout the data one register by one register. 

   

Many thanks for your help.

   

Kind Regards

   

Wesley 

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You are referring to the minimum buffer size which is 16 bytes in your case. Actually in last project post buffer size was set to 32.

   

Your selected buffer size will limit how many bytes you may send (and in parallel receive) before reading them off. So with your current algorithm the actual value is quite sufficient.

   

A problem can occur when the transmission is fast and the fifo gets empty: The ss-line will get high, indicating the slave a transaction end. To avoid this you may try:

   
        
  • Remove the ss-line from the SPIM component.
  •     
  • Add an output pin without hardware connection, strong drive initially high.
  •     
  • Manually (programmatically 😉 pull the new ss pin low before accessing the SPIM and release to high when done.
  •    
   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob,

   

Many thanks.

   

Sorry, I was confused by the datasheet :). If so, the SPI buffer size should not a problem? 

   

I use logic analyzer analyze the signals, seems the ss signal is ok? the screenshot is attached. The problem is from register '196' in MOSI, there is no any data in MISO, then I can only get part of the data, e.g. I only get 4-axis data of the 6-axis motion sensor.

   

Do you have thought about that?

   

Thanks a lot.

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

But you are aware that the gyro output must be zero when the MPU9250 is not rotating around any axis?

   

 

   

Bob

0 Likes
Anonymous
Not applicable

But if I change the reading sequence, there is always some data cannot be readout, either gyro or accelerometer, and only up to 4-axis data can be read. very strange.... The MPU can well communicate with I2C program, but the project requires SPI, which drive me crazy...

   

Best 

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Can you post your actual project.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob, 

   

Happy New Year! I wish you had a nice Christmas!

   

I have attached the project below, along with the MPU9250 documents.

   

Currently I am still trying to readout the 6-axis accelerometer and gyroscope data, and still only 4-axis data can be readout. If possible, could you help me have a look and give some feedbacks? 

   

Many thanks for your kind help.

   

Kind Regards

   

Wesley

0 Likes
Anonymous
Not applicable
        Hi, I can not connected cy8ckit-043 whis my pc (здравствуйте, я не могу соеденить плату cy8ckit-043, с моим компьютером, не может определиться внутри программ creator и programmer   
0 Likes

Not a good idea to hijack a foreign thread. Please create a new thread in the PSoC4 forum.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi Rob,

   

I wish all is well.

   

I finally got the program worked! Thanks a lot for your continuous kind help, I do appreciate that.

   

Many thanks again.

   

Kind Regards

   

Wesley

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You are always welcome, Lesley.

   

 

   

Bob

0 Likes