Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RPi4: 'Error 90 performing SPI data transfer.' #997

Closed
jesperandersson89 opened this issue Mar 2, 2020 · 5 comments
Closed

RPi4: 'Error 90 performing SPI data transfer.' #997

jesperandersson89 opened this issue Mar 2, 2020 · 5 comments
Labels
area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins bug Something isn't working

Comments

@jesperandersson89
Copy link

"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"

@jesperandersson89 jesperandersson89 added the bug Something isn't working label Mar 2, 2020
@joperezr joperezr added the area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins label Mar 2, 2020
@joperezr joperezr added this to the vNext milestone Mar 2, 2020
@joperezr
Copy link
Member

joperezr commented Mar 2, 2020

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.

@jesperandersson89
Copy link
Author

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)

@joperezr
Copy link
Member

joperezr commented Mar 2, 2020

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?

@jesperandersson89
Copy link
Author

jesperandersson89 commented Mar 12, 2020

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?)

@joperezr
Copy link
Member

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.

@ghost ghost locked as resolved and limited conversation to collaborators Oct 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Device.Gpio Contains types for using general-purpose I/O (GPIO) pins bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants