2017-02-28 07:56 AM
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:
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
.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.
nullSolved! Go to Solution.
2017-02-28 10:32 AM
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?
2017-02-28 08:07 AM
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
2017-02-28 08:18 AM
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.
2017-02-28 08:19 AM
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.
2017-02-28 09:28 AM
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 waitSPI4->DR = addr|0x80; // Reading from addr
while(!(SPI4->SR & SPI_SR_TXE)){}; // Wait for empty bSpiData = SPI4->DR; // Read rcvd dataSPI4->DR = 0xFF; // Write 2nd byte
while(SPI4->SR & SPI_SR_BSY){}; // bSpiData = SPI4->DR; //ACCL_CSHI();
delayLoop(10); // post CS delayreturn bSpiData;
}Putting *(uint8_t*) anywhere before SPI4->DR breaks the function. Reads or writes.
Any more suggestions?
2017-02-28 09:40 AM
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 delayreturn bSpiData;
}Resulting in:
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
2017-02-28 10:32 AM
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?
2017-02-28 10:39 AM
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, givenhspi4.Init.DataSize = SPI_DATASIZE_8BIT;
I am not going to investigate why it didn't.
JW
2017-02-28 10:43 AM
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
2017-03-01 12:14 AM
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.