dotnet / iot

This repo includes .NET Core implementations for various IoT boards, chips, displays and PCBs.
MIT License
2.18k stars 586 forks source link

SPI on Raspi: Hardware CS select is not working #1125

Closed pgrawehr closed 4 years ago

pgrawehr commented 4 years ago

For each SPI bus (up to 6 on the Raspi4), there are 2 or 3 designated pins for Chip Select (CS)*. The underlying hardware driver normally expects that one of these is also used. For SPI0, pins 7 and 8 serve as CS1 and CS0 respectively, when set to mode ALT0.

Problem 1: This doesn't work. When setting pin 8 to ALT0, the Chip never answers (to be investigated in detail with a scope, but I don't have mine at hand right now).

Problem 2: Even though the SpiConnectionSettings structure takes this member and sets it in the driver, this has also no effect, because it doesn't set the pin mode.

Problem 3: Many (all?) bindings fail to control the CS line at all, relying on the low-level driver, which can't work because of Problem 2.

We should:

CC: @Ellerbach, as you've had some experience with SPI, I think

(*) See Alternate Pin Assignments in the BCM2711 ARM Peripherals Guide.

krwq commented 4 years ago

@pgrawehr can you include exact repro steps? (what to put in config.txt; example device you are using and sample code)

Ellerbach commented 4 years ago

I'll try but so far I did not experience this issue. I had to use software CS selection sometimes because of the way the end device was working. And yes, the config.txt and anything that will help to recreate the same hardware setup and software setup is needed in this case. Version of the OS you are running as well to recreate the full conditions.

pgrawehr commented 4 years ago

I've got example code to reproduce the behavior, but it needs a bit of cleanup. I'll provide more information later today.

pgrawehr commented 4 years ago

How to reproduce the problem To reproduce, check out my branch https://github.com/pgrawehr/iot/tree/BoardApproach3 (PR #1128 ), then run the sample in devices/Board/samples

boot/config.txt only contains the relevant line dtparam=spi=on.

After booting, we have the following pin configuration (relevant for this case are BCM pins 9, 10, 11 and 8):

pi@raspberrypi:~ $ gpio readall
 +-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 | ALT4 | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 1 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO | ALT0 | 0 | 21 || 22 | 0 | OUT  | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT  | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 | ALT4 | 1 | 27 || 28 | 1 | ALT4 | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 | ALT4 | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | ALT0 | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 | ALT0 | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 4B--+---+------+---------+-----+-----+

This shows that the CS line (here named CE0) is set to out and high.

The sample application reads from an MCP3008 connected to these pins (the CI test setup should work for it). The first test runs the MCP with software controlled CS settings (Pin 8 is set to output and manually controlled). This works fine.

The second test uses hardware CS and therefore sets pin 8 to ALT0. Now it only reads Zero values, which is certainly not correct.

How to fix it After adding an extra line with dtoverlay=spi0-hw-cs to /boot/config.txt, this already looks better after startup:

 |  10 |  12 |    MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO | ALT0 | 0 | 21 || 22 | 0 | OUT  | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK | ALT0 | 0 | 23 || 24 | 1 | ALT0 | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | ALT0 | CE1     | 11  | 7   |

And magically... both tests pass now!

Conclusion So this is solved, however the documentation for this behavior is ... suboptimal. And it does mean that the second parameter in public SpiConnectionSettings(int busId, int chipSelectLine = -1) now does have a meaning. If it is -1, everything will be as before, but if it is 0 (what at least some samples do), the spi0-hw-cs overlay needs to be enabled, or the device won't work.

Ellerbach commented 4 years ago

So this is solved

So that's the good news!

however the documentation for this behavior is ... suboptimal

Yes, I agree. We were discussing that with @krwq few weeks ago. So as soon as we'll have a bit of bandwidth, SPI, I2C and Serial activation and setup should be better documented. That would include using external dongles as well.

pgrawehr commented 4 years ago

So as soon as we'll have a bit of bandwidth, SPI, I2C and Serial activation and setup should be better documented. That would include using external dongles as well.

I think the whole thing will become much simpler for the user once we have the pin management in (see #1128). Once this works, we can suggest a single set of config.txt settings (or maybe two, for Pi3 and Pi4), that will work for most situations. Because with that, once the kernel drivers are loaded, the library can handle all pin assignments automatically.

Ellerbach commented 4 years ago

@pgrawehr the spi0-hw-cs solution you mention is depreciated. I've been creating documentation on how to active all this properly with the new dtoverlays. If you want, you can check that your scenario is working with the new dtoverlays and also the documentation if anything is not clear enough.

krwq commented 4 years ago

@pgrawehr @Ellerbach can this be closed now?

Ellerbach commented 4 years ago

@krwq , fine for me to close as it seems to be exactly as I described now. It has evolved over time. And more consistent now. Now, that can be reopen if the behavior will change one more time.

krwq commented 4 years ago

Sounds good, feel free to re-open if there is something unresolved here