cancel
Showing results for 
Search instead for 
Did you mean: 

SPI data register alwas return 0xFF when execute couninously

raphaelplante
Associate II
Posted on November 26, 2016 at 00:19

The original post was too long to process during our migration. Please click on the attachment to read the original post.
2 REPLIES 2
Posted on November 27, 2016 at 12:52

In main, you write to SPI->DR but you don't read back from it after the frame has finished. This leaves the RXNE bit set, so that subsequently when you call SPI_Read() the first time, SPI->DR is read immediately after it has been written, thus you read the byte which was received in the previous frame.

Debugging/single-stepping hides this, as frame is sent/received faster than you single-step, thus you will always see the last received frame, unlike the processor core which at full throttle is fast enough to read out the previous received frame.

The solution is to write a short and simple routine which will write DR/wait until both TXE and RXNE are set/read DR, and use only that for transmitting/receiving SPI frames throughout the whole program.

I don't claim doing this your program will run as expected, but this is something you ought to fix anyway. Another suggestion is to get an oscilloscope/LA to help with SPI.

---

> I need to do it without the libraries for school.

I applaud this. May I know which school is it?

Please allow me a couple of style-related comments:

- in function headings, *always* use (void) if function has no parameters. Using and empty () is disallowed by C99 and later (even if some compilers don't frown upon it)

- keep the comments in English - in today's global world this comes handy when selling code to abroad or trying to achieve some sort of certification

- keep comments consistent with code - your SPI initialization in comments hints that you are using 16-bit frames

- don't get allured with ''I'll quickly code this and clean up/comment/document later'' approach; be systematic in commenting/documenting (e.g. what's the purpose of writing 0xC0 to register 0x20?)

- use #defines for symbolic names wherever appropriate (what's register 0x20 and what's value 0xC0?), don't use ''magic values'' - I bet there is a header such defines for that particular accelerometer out there in the code examples - find it and use it (or write your own, but that's no fun)

- avoid using read-modify-write (|= / &+)to registers wherever possible - e.g. when setting up SPI, you know the entire content of the control registers, so simply construct that value using the CMSIS symbols, and write it into that register at once:

    SMORF_ADC_SPI->CR1 = 0

      OR ( 1     * SPI_CR1_CPHA    )     /* Clock Phase -- shift, then sample */

      OR ( 0     * SPI_CR1_CPOL    )     /* Clock Polarity  -- CKL idle is 0 */

      OR ( 1     * SPI_CR1_MSTR    )     /* Master Selection */

      OR ( SPI_CR1_BR__8 * SPI_CR1_BR_0 )     /* Baudrate -- HCLK=160MHz -> P2CLK=80MHz -> baud=10MHz */

      OR ( 1     * SPI_CR1_SPE     )     /* SPI Enable */

// *** OFF ***      OR ( 0     * SPI_CR1_SPE     )     /* SPI Enable */

      OR ( 0     * SPI_CR1_LSBFIRST)     /* Frame Format -- 0 -> MSB first (''normal'' SPI) */

      OR ( 0     * SPI_CR1_SSI     )     /* Internal slave select */

      OR ( 0     * SPI_CR1_SSM     )     /* Software slave management */

      OR ( 0     * SPI_CR1_RXONLY  )     /* Receive only */

      OR ( SPI_CR1_DFF__16 * SPI_CR1_DFF )     /* Data Frame Format - 16-bit */

      OR ( 0     * SPI_CR1_CRCNEXT )     /* Transmit CRC next */

      OR ( 0     * SPI_CR1_CRCEN   )     /* Hardware CRC calculation enable */

      OR ( 0     * SPI_CR1_BIDIOE  )     /* Output enable in bidirectional mode */

      OR ( 0     * SPI_CR1_BIDIMODE)     /* Bidirectional data mode enable */

    ;

(I have written previously #defines for non-single-bit-bitfields in the registers, these are largely missing from the CMSIS header - I have been crying at every possible forum for ST to fix this ever since I started with the STM32s several years ago, but they are too busy with Cube and stuff to allocate time to do the right thing.

 I also have a #define OR | as I come from Pascal background and I despise the C(++ ++) practice of minimizing keystrokes at the expense of human readability - unfortunately this #define collides with some STM32F headers so that sometimes has to be worked around..)

This is not only faster (avoiding unnecessary read and/or multiple read/write accesses), but also sticking to this technique you'll avoid inadvertent bugs with registers where read has side-effects in hardware (there are rare but that's why it's better to develop a habit of not using unnecessary and potentially dangerous operations).

- use the GPIO_BSRR register to change GPIO output pins levels rather than GPIO_ODR - this helps avoiding atomicity problems once you'll start to use interrupts and change GPIO output levels in them

JW

raphaelplante
Associate II
Posted on November 28, 2016 at 02:44

Thank you very much, I'm from Polytechnique Montreal in Canada. Reading the data register at the end of each frame did solve part of the problem. The other part was when configuring 0x20 (control register) with 0xC0, I was in fact disabling the x,y,z output data. I am now successfully able to read the data register value.