Main Site Documentation

Defining cpu.pins for chip select to use SPI


#1

I need some help in defining SPI connections and module pins. I am using a FEZ Raptor, and have a Breakout Module that I am connecting to socket $3 (S-type) to connect several AD converters. I know that the Breakout module attaches to another socket, but it appears to be a 1:1 extension of the socket pins, so it should allow my external circuit to access board SPI and digital outputs.
Each ADC will use the same SPI module, but will have different chip selects. I have studied the data sheets for the module, the SoM, and the uProcessor, but I have not found a way to route the various socket/pin to uProcessor pins (CPU.PIN) as to define the chipselect in a fashion that is portable to other sockets, and to non-Getgeteer NETMF applications.
Here is what I have tried:


            Dim socket As Socket = socket.GetSocket(3, True, breakout_TB10, "")
            _SPI = socket.SPIModule
            ' socket 3 (S) pin 3 (type GPIO!) on the Raptor connects to "PB1" 
            ' socket 3 (S) pin 5 (type GPIO) on the Raptor connects to "PB3"

            Dim cpupin(0) As Cpu.Pin
            cpupin(0) = DirectCast(socket.Pin.Three, Cpu.Pin)
            Dim Monitor = New Thread(Sub() ADC(cpupin, _SPI))
            Monitor.Start()

Thanks…

If anyone can suggest how to approach this problem I would appreciate it.

Thanks.


#2

Gadgeteer and SPI means you only get to define the socket your SPI device connects to and it dictates the connections you need to make. If you need to use a non-standard configuration, you’re going to need to mix the use of Gadgeteer and netmf core SPI functions.

If you were coding in C# I would set up and give you some example code… basically you’re kind of on the right path, define the socket, use the pins as you need in the constructor of the SPI. You just need to make sure you use the netmf SPI not the Gadgeteer variant


#3

Brett, thanks for the reply.
I will keep trying - I guess Gadgeteering puts an opaque layer that makes it easier for the standard modules, but harder for everything else.
What I need is a mapping between Raptor pins (like PB1) and Hardware.cpu.pin (listed as GPIO…). Even an example in C# would be helpful.


#4
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;

namespace SpiTest
{
    public partial class Program
    {
        private GTI.SPI _spi;
        private GTI.SPI.Configuration _spiConfig;
 
        void ProgramStarted()
        {
            var socket = GT.Socket.GetSocket(3, true, null, null);
            _spiConfig = new GTI.SPI.Configuration(false, 0, 0, false, true, 12000);
            _spi = new GTI.SPI(socket, _spiConfig, GTI.SPI.Sharing.Shared, socket, GT.Socket.Pin.Six, null);
        }
    }
}

#5

Or this?


#6

Hi Bill

Thanks for the suggestions. On your first suggestion, I cannot see SPI in Gadgeteer.interfaces. The interface has I2Cbus, and most of the other expected items, but no SPI, at least in my install for the Fez_Raptor…
The version of Gadgeteer.net that I am using is 2.42.0.0

You suggestion for Cpu.Pin does work fine.


#7

You need to add a reference to Gadgeteer.SPI


#8

Thanks for the replies, hopefully I am getting closer. To restate what I am trying to do, I have a class that addresses an array of ADCs sharing SPI lines with separate chip selects. My class, which works fine in a NETMF application (not Gadgeteer), is created by passing a reference to the chip select pins, and the SPI module identifier. Periodically it samples the ADC where it instantiates an SPI, samples the array, then disposes of the SPI, so other classes can use this resource.
This was derived from the example “Accessing multiple SPI devices” at https://www.ghielectronics.com/docs/14/spi

Here is my code as it stands. This throws an exception near the bottom in the Try…Catch sequence, and the details of the exception is at the end.

       Public Sub ProgramStarted()
                        bmap = New Bitmap(CInt(display_T43.Width), CInt(display_T43.Height))
            Me.display_T43.SimpleGraphics.DisplayText("Biospherical Instruments Inc.", Resources.GetFont(Resources.FontResources.RockwellCondBoldBSI), Gadgeteer.Color.Blue, 1, 250)

            ' Assign the Window to MainWindow; rendering it to the LCD.

            LabelTitle = New Library.Library.Labels(Me.display_T43, Gadgeteer.Color.Black, Gadgeteer.Color.FromRGB(0, 255, 255), 0, 25, 300, 25, Resources.GetFont(Resources.FontResources.Arial20))
            LabelxPos = New Library.Library.Labels(Me.display_T43, Gadgeteer.Color.Black, Gadgeteer.Color.FromRGB(0, 255, 255), 0, 50, 300, 25, Resources.GetFont(Resources.FontResources.Arial20))
            LabelyPos = New Library.Library.Labels(Me.display_T43, Gadgeteer.Color.Black, Gadgeteer.Color.FromRGB(0, 255, 255), 0, 75, 300, 25, Resources.GetFont(Resources.FontResources.Arial20))
            LabelLength = New Library.Library.Labels(Me.display_T43, Gadgeteer.Color.Black, Gadgeteer.Color.FromRGB(0, 255, 255), 0, 100, 300, 25, Resources.GetFont(Resources.FontResources.Arial20))

            bargraph = New Library.Library.BarGraph(led_Strip)
            
            ' Define the socket
            Dim socket3 As Socket = Socket.GetSocket(3, True, Nothing, Nothing)

            ' define an arbituary configuration
            Dim _spiConfig As gti.SPI.Configuration = New gti.SPI.Configuration(False, 0, 0, False, True, 12000)

            ' define a SPI so I can identify the module assignment - the socket.pin.# will be ignored and redefined later
            Dim spiAD As gti.SPI = New gti.SPI(socket3, _spiConfig, Interfaces.SPI.Sharing.Shared, socket3, Gadgeteer.Socket.Pin.Three, Nothing)

            ' the module assignment to pass on to the class
            Dim _spiModule As SPI_module = spiAD.SPIModule

            ' define the first chip select pin.  Only 1 AD here            
            Dim cpupin(0) As Cpu.Pin
            cpupin(0) = GHI.Hardware.G400.Pin.PB1  ' would be nicer to set to Gadgeteer.socket.pin.three

            Dim Monitor = New Thread(Sub() ADC(cpupin, _spiModule))
            Monitor.Start()
            Exit Sub
...
end sub

       Private Shared Sub ADC(pin() As Pin, spimodule As SPI_module)
           Dim admonitor As New AD7799(pin, spimodule)
        End Sub
...
End Class

Public Class AD7799
    Dim ad As AD7799
    Private _spi As SPI
    Private _ChipSelectBarPin() As Pin
    Private _spi_mod As Microsoft.SPOT.Hardware.SPI.SPI_module
    Private _SPI_config() As SPI.Configuration

    Public Sub New(pn() As Microsoft.SPOT.Hardware.Cpu.Pin, spi As SPI.SPI_module) ' spi_mod As Microsoft.SPOT.Hardware.SPI.SPI_module)
        _ChipSelectBarPin = pn
        ReDim _SPI_config(pn.Length - 1)
        For i As Integer = 0 To CInt(_ChipSelectBarPin.Length - 1)
            _SPI_config(i) = BuildConfiguration(_ChipSelectBarPin(i), spi)
        Next

        Try
            _spi = New SPI(_SPI_config(0))
        Catch ex As Exception
            Debug.Print(ex.Message)
            Debug.Print(ex.StackTrace)
            Stop
        End Try
        ' reset the 7799 here ************************
....
End Class

When I execute this, the correct CS pin is sent to the AD7799 class, and the correct SPI module is also seen. The problem is that the code throws an exception at the Try…Catch section as follows:
#### Exception System.InvalidOperationException - CLR_E_INVALID_OPERATION (6) ####
#### Message:
#### Microsoft.SPOT.Hardware.Port::ReservePin [IP: 0000] ####
#### Microsoft.SPOT.Hardware.SPI::.ctor [IP: 0022] ####
#### THdeckboxProto1.AD7799::.ctor [IP: 0053] ####
#### THdeckboxProto1.THdeckboxProto1.Program::ADC [IP: 0005] ####
#### THdeckboxProto1.THdeckboxProto1.Program+_Closure$__1::_Lambda$__1 [IP: 000b] ####
A first chance exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.dll
Exception was thrown: System.InvalidOperationException
Microsoft.SPOT.Hardware.Port::ReservePin
Microsoft.SPOT.Hardware.SPI::.ctor
THdeckboxProto1.AD7799::.ctor
THdeckboxProto1.THdeckboxProto1.Program::ADC
THdeckboxProto1.THdeckboxProto1.Program+_Closure$__1::_Lambda$__1


#9

The exception is because you’re using a pin that is already reserved or in-use. When in your application execution is it thrown? Does it work for a while and then generate this, or does it never work? You say it works fine in a netmf console app - what adjustments did you make to your code for Gadgeteer?

Do you need the SPI setup in ProgramStarted()? Can you not just do everything in your class?

Basically, what’s the “problem” you’re trying to solve that means you need to move away from the netmf code?


#10

Hi Brett:
The exception is thrown near the end, in at the statement _spi = New SPI(_SPI_config(0))
It is thrown the first time, always. In the non-Gadgeteer code it is never thrown.
I made not adjustments in the class AD7799 from the code in NETMF. In the calling code, I attempted to gather the needed parameters (spi.module and cpu.pin from the socket #, so they could be passed as cpu.pin(), and spi_module. In examing the parameters at where the exception is thrown they appear to be correct.
I do not need the SPI setup in the ProgramStarted, but I do want to get the SPI_module that is assigned to that socket. I would also like to define the chip select on the basis of the socket number and the socket pin, but I have not found a way. This is not essential, but it seems neater.
As I see it, the problem is to do this in a way that facilitates moving from a Gadgeteer rapid prototype, to a solution that would probably utilize a G400-S hosted in a custom board.
I tried putting a wrapper around the class, and hard codes the pins and spi_module, but the same error happened.
Is there something about the Gadgeteer framework that is reserving the SPI module and preventing it from being used?


#11

so really what you want to achieve is to instantiate your class based on a socket chosen at design time without having to override the SPI port selection and the !CS lines. That in my C# mind is reasonably straightforward, this becomes a custom “module” and your class is the “driver”, in ProgramStarted() you just instantiate it with the socket you want.

How that translates to VB, scratching my head sorry. :frowning:

MyObj = new MyClass(3) // put it on socket 3, same as the initialisation routines in the generated code is