cancel
Showing results for 
Search instead for 
Did you mean: 

SPI 8bit data length

tau
Associate II
Posted on February 28, 2017 at 16:56

Hi, I'm setting up SPI comms with a slave device. (ADXL350 accelerometer) This is on an STM32F767ZIT6. I should point out I put this on a nucleo -'F746 board but it's all working fine so far at 200MHz with other peripherals presenting no problem.

I've selected 8 bit data size, but am seeing 16 clocks on a scope. I use a read function to read address 0x00, the device's ''who_am_I'' register, and get 0xE5 back. In theory this is ok.

However, I see the image here:

0690X00000603hHQAQ.jpg

Yellow = MOSI

Cyan = MISO

Red = CLK

Green = _CS

The accelerometer is replying <0xE5> 3 times (trace 2 in cyan) because of this 16bit data size. If I set it to 4bit data size, I get 8 data clocks. But then I get a nybble in the low byte and a nybble in the high byte.

https://community.st.com/0D50X00009XkeupSAB

http://www.st.com/content/ccc/resource/technical/document/technical_note/58/17/ad/50/fa/c9/48/07/DM00054618.pdf/files/DM00054618.pdf/jcr:content/translations/en.DM00054618.pdf

I use my own transfer code, but copied HAL initialisation code as follows:

void spiSetup(void)

{

   hspi4.Instance = SPI4;

   hspi4.Init.Mode = SPI_MODE_MASTER;

   hspi4.Init.Direction = SPI_DIRECTION_2LINES;

   hspi4.Init.DataSize = SPI_DATASIZE_8BIT;

   hspi4.Init.CLKPolarity = SPI_POLARITY_HIGH;

   hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;

   hspi4.Init.NSS = SPI_NSS_SOFT;

   hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;

   hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;

   hspi4.Init.TIMode = SPI_TIMODE_DISABLE;

   hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

   hspi4.Init.CRCPolynomial = 7;

   hspi4.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;

   hspi4.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

   if (HAL_SPI_Init(&hspi4) != HAL_OK)

   {

      //Error_Handler();

      while(1){};

   }

   SPI4->CR1 |= SPI_CR1_SPE;

}

All I'm doing is writing to SPI4->DR and waiting for the TXNE or BUSY flags to clear.

Any help would be appreciated.

null
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on February 28, 2017 at 18:32

Of course it should've been *(uint8_t *)& ... :blushing: Mea culpa.

JW

[EDIT] and more like *(__IO uint8_t *)&SPI->DR

[EDIT2] have you read the Data packing subchapter of SPI chapter in RM?

View solution in original post

11 REPLIES 11
Posted on February 28, 2017 at 17:07

You have to write only 8 bits to the SPI_DR, see 'data packing' in the SPI chapter of RM.

*(uint8_t *)SPI->DR = data;

There may be some function or macro for this in Cube; I don't Cube so I don't know.

JW

tau
Associate II
Posted on February 28, 2017 at 17:18

So after just showing a colleague, we tried transmitting just one byte. I still get the 0xE5 in the data register as expected, and this time there are only 16 clock cycles, as expected normally.

But what if I want to read 2 bytes?

Address +byte1 + byte2 = 3 bytes. But I would be sending 4, or most probably 6, because any write to the DR incurs a 16clock transmit overhead.

Please tell me this is not a bug, so I can continue to investigate this part for our inverters. DP FPU, 200MHz, triple interleaved 12bit ADC ticks all my other boxes.

S.Ma
Principal
Posted on February 28, 2017 at 17:19

It seems that a physical write on the DR must be 8 bit, otherwise, the MSB and LSB will be queued onto the FIFO and 2x8bit will be transmitted.

tau
Associate II
Posted on February 28, 2017 at 18:28

Thanks for the suggestions. Not fixed it yet. I've resorted to hardcoding values in the test function.

So this bit (in bold):

*(uint8_t *)SPI4->DR = data;

breaks my function. I have a working SPI transmit that writes two bytes at once out the fifo, and when I downcast anything to a uint8 ptr, it breaks. CS goes low, and then I get an unhandled interrupt which I'm going to guess is a hard fault / misalignment issue.

Here's my actual code:

/*

* Accelerometer SPI layer data transfers

* */

uint8_t readByte(uint8_t addr)

{

      ACCL_CSLO();

      delayLoop(5); // small CS wait

      SPI4->DR = addr|0x80; // Reading from addr

      while(!(SPI4->SR & SPI_SR_TXE)){}; // Wait for empty

      bSpiData = SPI4->DR; // Read rcvd data

      SPI4->DR = 0xFF; // Write 2nd byte

      while(SPI4->SR & SPI_SR_BSY){}; //

      bSpiData = SPI4->DR; //

      ACCL_CSHI();

      delayLoop(10); // post CS delay

      return bSpiData;

}

Putting *(uint8_t*) anywhere before SPI4->DR breaks the function. Reads or writes.

Any more suggestions?

tau
Associate II
Posted on February 28, 2017 at 18:40

Fixed it:

/*

* Accelerometer SPI layer data transfers

* */

uint8_t readByte(uint8_t addr)

{

static uint8_t* spiDrPtr = (uint8_t*)&SPI4->DR;

ACCL_CSLO();

delayLoop(5); // small CS wait

*spiDrPtr = addr|0x80; // Reading from addr

while(!(SPI4->SR & SPI_SR_TXE)){}; // Wait for empty

bSpiData = *spiDrPtr; // Read rcvd data

*spiDrPtr = 0xFF; // Write 2nd byte

while(SPI4->SR & SPI_SR_BSY){}; //

bSpiData = *spiDrPtr; //

ACCL_CSHI();

delayLoop(10); // post CS delay

return bSpiData;

}

Resulting in:

0690X00000603hRQAQ.jpg

And as for why it replies 0xE5 during the first byte, I don't know/care atm.

Thanks for the ''pointers'' guys, hope this helps someone else

Posted on February 28, 2017 at 18:32

Of course it should've been *(uint8_t *)& ... :blushing: Mea culpa.

JW

[EDIT] and more like *(__IO uint8_t *)&SPI->DR

[EDIT2] have you read the Data packing subchapter of SPI chapter in RM?

Posted on February 28, 2017 at 18:39

As I've said I don't Cube, but judging from

https://community.st.com/0D50X00009XkdsnSAB

  I'd say that that function should have used the 8-bit write, given

 hspi4.Init.DataSize = SPI_DATASIZE_8BIT;

I am not going to investigate why it didn't.

JW

Posted on February 28, 2017 at 18:43

And as for why it replies 0xE5 during the first byte, I don't know/care atm.

Maybe that's a remainder from previous communication.

Try to reset the accelerometer (if it does not have an explicit reset method then power off/on) whether it makes any difference.

JW

tau
Associate II
Posted on March 01, 2017 at 09:14

Thanks for the help, and I missed the address ampersand too Jan - until it came to creating a pointer myself.

I'll probably end up using your method as I want to write and test this code across several MCUs (STM32F7 / STM32H7 / KV58F / SAMV71) and having something I can stick in a header file based on MCU definition is good.