STM32F429I-Discovery board has an L3GD20 3-axis gyroscope onboard connected to SPI channel 5. In this article we'll try to get it up and running. I will continue where we left off last time - a working example with blinking LEDs and UART.
So, let us look at the devkit connections, as defined in Discovery board documentation:
- MOSI is on PF9
- MISO is on PF8
- SCK is on PF7
- Chip-select (CS) is in PC1
- Interrupt 1 is on PA1
- Interrupt 2 is on PA2
In addition to that, NCS_MEMS_SPI has been defined. That would be our CS. And last bunch are interrupt pins. Neat.
Another thing we should worry about (it's a pretty common source of headache) are SPI bus setup. Generated setup in spi.c states:
Let's review it and compare to the data in datasheet. Sadly, they don't just tell you mode SPI is working in, so you have to read the signal time chart and figure it out on your own:
- Instance: SPI5 is what we want, yes
- Mode: Master mode - we will be initiating the communications
- Direction: 2 Lines. That's what we have and want. Apparently, there's a support for single-wire half-duplex comms as well, but that's not for us
- Datasize: 8bit. True. All the registers are 8bit, wider words are sent as pairs of high/low bytes
- Clock polarity (CPOL): Idle state is high, so polarity is high
- Clock phase (CPHA): Sampling seems to be done on the trailing edge, so this should be SPI_PHASE_2EDGE
- NSS (Slave select) will be done in software for now, by manually pulling CS pin low before transfer, with subsequent pull back up once transfer is done. It is possible to use hardware NSS, but it requires disabling the SPI master after transfer to pull it back up (just an implementation in STM32 HAL)
- Baud Rate Prescaler is a clock divider, which sets the transfer speed. Leave it be for now
- First Bit should be the most significant bit (MSB) as per gyro datasheet
- We are not interested in TI mode for now, so leave it disabled
What is happening here, is:
- We define default response as error, just to be sure, that it gets changed to HAL_OK
- define a 2 byte wide transmit buffer (with last spot as NULL terminator) First is the byte (command) we send. We want to read (0x80) register 0x0F, then we send bunch of zeros as a dummy payload to give chance to the chip to respond.
- define a 2 byte wide receive buffer (with last spot as NULL terminator). First byte is dummy receive, normally filled with 0xFF (no data), the second one will contain the response from the chip
- pull down our CS pin, to indicate to the slave, that we are talking to it
- Do the actual transceiving of the data
- pull back up the CS pin, to tell the chip, that we are done with it
- check the response status code and print out the data or code received
- kill the thread, for we are done with it
All that's remaining, is just starting the task and let it run. I will add a new handle and reduce the priorities of blinky tasks to avoid them interrupting our transmit, since it is in blocking mode, that might mess things up:
I'm not particularly interested in implementing full driver for the gyro, that can be left as an exercise for the reader. There should be plenty of those already available online.
As usual, sources on GitHub have been updated to include all of the above. Next up: Part V: SPI with DMA