"Describe the bug"
I'm trying to receive analog readings from an esp32 connected to my Raspberry Pi 4 over SPI.
The code below works perfectly on an Raspberry Pi 3B+, but when I try to run the _exact same_ code on a Pi 4 then adc_0.Read(tmp) gives me this "unGoogleable" error: _Error 90 performing SPI data transfer._
Does anyone have any idea what the problem might be?
C#-code: (.NET Core 3.1)
using System;
using System.Device.Spi;
namespace SPITest1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var spiTester = new SpiTester();
var result = spiTester.Test1();
}
}
public class SpiTester
{
SpiDevice adc_0;
private readonly int clockFrequency = 10_000_000;//48_000_000; //48MHz;
private readonly SpiMode spiMode = SpiMode.Mode3;
private readonly int dataBitLength = 8;
private ushort[] sampleArray;
private byte[] tmp;
public SpiTester()
{
sampleArray = new ushort[16 * 1000];
tmp = new byte[16 * 1000 * 2];
SpiConnectionSettings spiSettings_0 = new SpiConnectionSettings(0, 0)
{
ClockFrequency = clockFrequency,
Mode = spiMode,
DataBitLength = dataBitLength
};
adc_0 = SpiDevice.Create(spiSettings_0);
}
public ushort[] Test1()
{
Array.Clear(sampleArray, 0, sampleArray.Length);
Array.Clear(tmp, 0, tmp.Length);
adc_0.Read(tmp);
for (int i = 0; i < sampleArray.Length; i++)
{
sampleArray[i] = (ushort)(tmp[i * 2 + 1] | tmp[i * 2] << 8);
}
return sampleArray;
}
}
}
Arduino-code:
#include <Arduino.h>
#include <SPI.h>
#include <ESP32DMASPISlave.h>
typedef union
{
uint16_t Sample;
struct
{
uint8_t LowBits;
uint8_t HighBits;
} SampleBits;
}t16Byte;
const int numberOfChannels = 16;
const int numberOfSamples = 1000;
static const uint32_t BUFFER_SIZE = 2 * (numberOfChannels * numberOfSamples);
ESP32DMASPI::Slave slave;
uint8_t* spi_slave_tx_buf;
t16Byte analogReadings[numberOfChannels * numberOfSamples];
void setup()
{
Serial.begin(115200);
spi_slave_tx_buf = slave.allocDMABuffer(BUFFER_SIZE);
slave.setDataMode(SPI_MODE3);
slave.setMaxTransferSize(BUFFER_SIZE);
slave.setDMAChannel(2);
slave.setQueueSize(1);
// HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12
slave.begin(HSPI);
for (uint16_t i = 0; i < (numberOfChannels*numberOfSamples); i++)
{
analogReadings[i].Sample = i;
}
}
void loop()
{
if (slave.remained() == 0)
{
Serial.printf("Sending data!\n");
for (int sampleIndex = 0; sampleIndex < BUFFER_SIZE-1; sampleIndex +=2)
{
spi_slave_tx_buf[sampleIndex] = analogReadings[sampleIndex/2].SampleBits.HighBits;
spi_slave_tx_buf[sampleIndex+1] = analogReadings[sampleIndex/2].SampleBits.LowBits;
}
slave.queue(NULL, spi_slave_tx_buf, BUFFER_SIZE);
slave.yield();
Serial.printf("Data sendt!\n");
}
delay(500);
}
Expected behavior
adc_0.Read(tmp); should give me an array of data from my esp32.
Actual behavior
adc_0.Read(tmp); throws the following error:
Exception has occurred: CLR/System.IO.IOException
An unhandled exception of type 'System.IO.IOException' occurred in System.Device.Gpio.dll: 'Error 90 performing SPI data transfer.'
at System.Device.Spi.UnixSpiDevice.Transfer(Byte* writeBufferPtr, Byte* readBufferPtr, Int32 buffersLength)
at System.Device.Spi.UnixSpiDevice.Read(Span`1 buffer)
at SPITest1.SpiTester.Test1() in C:\Users\jesper.andersson\source\repos\SPITest1\SPITest1\Program.cs:line 46
at SPITest1.Program.Main(String[] args) in C:\Users\jesper.andersson\source\repos\SPITest1\SPITest1\Program.cs:line 12
dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.1.102
Commit: 573d158fea
Runtime Environment:
OS Name: raspbian
OS Version: 10
OS Platform: Linux
RID: linux-arm
Base Path: /home/pi/dotnet/sdk/3.1.102/
Host (useful for support):
Version: 3.1.2
Commit: 916b5cba26
.NET Core SDKs installed:
3.1.102 [/home/pi/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.App 3.1.1 [/home/pi/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.2 [/home/pi/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.1 [/home/pi/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.2 [/home/pi/dotnet/shared/Microsoft.NETCore.App]
Version of System.Device.Gpio : "1.0.0"
Thanks for logging the issue @jesperandersson89. Can you confirm that you enabled the SPI interface on your Pi 4? AFIK there aren't many differences with how the SPI bus work on pi 3B+ compared to 4.
Yes SPI should be enabled, below is my _config.txt_:
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on
# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18
# Additional overlays and parameters are documented /boot/overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-fkms-v3d
max_framebuffers=2
[all]
#dtoverlay=vc4-fkms-v3d
dtoverlay=w1-gpio
I'm using vsdbg for remote debugging, but I experience the same issue when i run the code locally on the Pi 4. (sudo ./SPITest1)
I haven't played much with the Pi4 but the code looks right to me, so unless there was some change in the pin layout with Pi4 I'm not sure what might be going on. Can you try doing a simple test with trying to communicate with the same device using python to see if that is successful? If not, this might be a problem with the SPI bus in your Pi or with your connection. I assume you used BCM pins 9, 10 and 11?
Fixed it!
The error comes from trying to read mode bytes than the SPI-buffer on Rasbian allows by default. (4096)
The solution is either to create a file _/etc/modprobe.d/spidev.conf_ with contents:
options spidev bufsiz=65536 (or preferred buffer size).
OR
Add this to _/boot/cmdline.txt_:
spidev.bufsiz=65536 (or preferred buffer size).
Reboot and check your work with cat /sys/module/spidev/parameters/bufsiz
Suggesting that someone fixes the cryptic error 90 that https://github.com/dotnet/iot/blob/master/src/System.Device.Gpio/System/Device/Spi/Devices/UnixSpiDevice.Linux.cs throws on line 227?
The problem here is Marshal.GetLastWin32Error(), because error 90 does not exist.
Ref. https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
Edit*:
(Hmmm... error 90 is EMSGSIZE - "Message too long" in unix.. so maybe I should have figured it out sooner?)
Awesome I'm glad you found the issue and I thank you for posting the fix here so people in the future can come back to this if they ever hit it. Feel free to open an issue for fixing error messages from our API since I agree we should try to flush as much info as possible here.
Most helpful comment
Fixed it!
The error comes from trying to read mode bytes than the SPI-buffer on Rasbian allows by default. (4096)
The solution is either to create a file _/etc/modprobe.d/spidev.conf_ with contents:
options spidev bufsiz=65536(or preferred buffer size).OR
Add this to _/boot/cmdline.txt_:
spidev.bufsiz=65536(or preferred buffer size).Reboot and check your work with
cat /sys/module/spidev/parameters/bufsizSuggesting that someone fixes the cryptic error 90 that https://github.com/dotnet/iot/blob/master/src/System.Device.Gpio/System/Device/Spi/Devices/UnixSpiDevice.Linux.cs throws on line 227?
The problem here is
Marshal.GetLastWin32Error(), because error 90 does not exist.Ref. https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
Edit*:
(Hmmm... error 90 is EMSGSIZE - "Message too long" in unix.. so maybe I should have figured it out sooner?)