Digi Connect ME 9210 - SPI

A have DC ME 9210 on way. Does anybody now how to setup SPI interface?

The SPI functions in NET+OS 7.3 is only NS9360 Rev A, NS9750 Rev A, ConnectCore 9C compatible.

Is somewhere same updates for this digi module?

Thanks Jirka

Did you ever hear back? I am working with a 9210 and would like to set up a SPI interface, but there is no documentation on the ME 9210 in the NetOS7.4 docs.

-Erik

HI,

I am not certain about the 9210, but I have the 9P module with the 9215 on it and I have SPI working OK. I started with the sample application and it worked with no problem on the 9P. You may have to change some definitions to get the right signal lines hooked up to get it to work on the 9210

Yeah, I was trying to avoid reverse engineering.

I did that for NetOS5/6 on the ME and practically had to rewrite the bsp to get it to work properly. The three months it took to do that almost bankrupted the company.

I was hoping that there were some ME9210 docs that came out late or something that Digi posted somewhere I can’t find.

-Erik

Getting SPI to work on the ME 9210 (or CC9P 9215) is pretty trivial because both have dedicated SPI interfaces. All you have to do is:

  • Setup the GPIO:

#define APP_SPI_MASTER_GPIO_CS 0
#define APP_SPI_MASTER_GPIO_CLK 5
#define APP_SPI_MASTER_GPIO_RXD 3
#define APP_SPI_MASTER_GPIO_TXD 7

if(NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_FUNC4_STATE, 0))
    return -1;

if(NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC4_STATE, 0))
    return -1;

if(NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_RXD, NA_GPIO_FUNC4_STATE, 0))
    return -1;

if(NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_TXD, NA_GPIO_FUNC4_STATE, 0))
    return -1;
  • Call NASpiRegisterDevice to setup the SPI Port (mode, bitrate, etc)

  • Use NASpiReadWrite (to read/write your data)

Note - There are a few references and things you should be aware of:

There is an SPI Master and Slave example (File -> New -> Sample Project)

The ME 9210 HRM has good information on pin multiplexing (Programming Considerations section) and the NS9210 HRM has all the information about the GPIO lines: http://www.digi.com/support/productdetl.jsp?pid=3510&osvid=0&s=375&tp=3

Mode information can be found here: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

Your read buffer has to be 32 byte aligned, so I use something like this to get around that issue:

char readBuf[BUFFER_SIZE + 32];
char *readptr;

readptr = readbuf + (32 - ((int)readbuf % 32));

.

In other words, reverse engineer it.

Taking a look at it, seems simple enough.

Thanks guys.

What is the recommended method to run multiple SPI slaves with the Connect ME 9210?

I need to run 2 SPI devices using the Connect ME 9210 as the SPI master.

On other embedded designs, I used the chip selects on the slaves connected to the I/O pins of the processor. The Connect ME 9210 exposes GPIO[0] which is referenced in the 9210 HW reference as a “SPI EN (dup)”. However, the other pins marked as “SPI EN (dup)” are GPIO[8] and GPIO[15]. Neither of these pins are exposed on the Connect ME.

Option 1: “SPI CLK (dup)” is exposed on GPIO[5], GPIO[12], and GPIO[13]. Is it possible to run all the slave chip selects from GPIO[0], wire one spi slave clock to GPIO[5], the other slave clock to GPIO[12] to “select” which spi slave is active?

Option 2: Use GPIO[0] as the chip select for the 1st spi slave, GPIO[6] as the chip select for the 2nd spi slave. The application code would need to disable the GPIO[0] as the automatic SPI EN and manually control GPIO[0] and GPIO[6] before and after calls to transfer information to/from the slave chips. Both slave chips would then use the same SPI CLK (GPIO[5]).

Any recommendations?

Hi,

THere are a couple of things to note with the SPI master.

If you are going to be sending very short messages you will find that there is a bit of a problem. The standard code uses NAuWait(1) to effectively poll for the transaction complete Flag. NAuWait uses a timer to provide very short and should delay for the number of microsecs defined by the parameter, but due to the way it is implemented it is unable to operate with very short delays.

Overall if you are doing a lot of transactions one after the other, there is an excessive delay between each transaction. I sorthed this out by changing code in “spi_master.c” as follows.

OLD CODE:
/* wait for spi done /
while (timeout && (!gTxFlag || !gRxFlag))
{
/
Should this be a tx_thread_sleep(1) or something in order to
* allow lower priority threads to run as well?
*/
if (bufferLength < 8000)
NAuWait(1);
else
tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(1));
timeout–;
}

NEW CODE:
/* wait for spi done /
while (timeout && (!gTxFlag || !gRxFlag))
{
/
Should this be a tx_thread_sleep(1) or something in order to
* allow lower priority threads to run as well?
*/
if (bufferLength < 8000) {
if (bufferLength > 1000)
NAuWait(1);
}
else
tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(1));
timeout–;
}

Hope this helps

Regards
Roy

That’s far from reverse engineering… That’s modifying the code to behave differently… It’s also why Digi provides the source…

It is reverse engineering the source…

Right now I am trying to figure out what the *$%#! they mean by “ring buffer”. I am getting quite confused with the SPI slave extern source…

I only have 1 buffer, that should be all I need. Right?

Digi really, really needs to learn what KISS means. I have been fighting this type of stuff for over five years now.

http://en.wikipedia.org/wiki/Ring_buffer

By the way, while this is a public forum, a less aggressive style would still be appreciated. New here, but already noticed a couple of these posts from you.

“By the way, while this is a public forum, a less aggressive style would still be appreciated. New here, but already noticed a couple of these posts from you.”

Sorry if I offended you. I learned to be a bit aggressive in my Digi forum posts back in '04. It was the only way Digi support would notice the post. This forum was the only online resource for Digi Dev at the time. They had really good phone support people, but not nearly enough of them (very overworked), so posting was often the fastest way to get an answer.

And, pardon me, but I got the SPI working with only a few lines of code, WITHOUT the ring buffer. I threw out the “example” and hacked it based on the API help file.

-Erik

I also wrote a small SPI slave application without ring buffer. But the callback function is never called when a character is received and I can’t figure out the reason.

Is it possible to post your working SPI slave app?

Thanks,
mrib

Here is the callback:
/////////////////////////////////////////////////////////

#define _POOL_OVERHEAD_SIZE 4 /* sizeof(void *) */
#define SPI_BUFFER_POOL_SIZE 64

static char gWriteData[SPI_BUFFER_POOL_SIZE * _POOL_OVERHEAD_SIZE];

static char gReadData[SPI_BUFFER_POOL_SIZE * _POOL_OVERHEAD_SIZE] attribute ((aligned(32)));

static void app_spi_raw_data_callback(void *buffer)
{
NASpiSlaveBufferType *spi_buffer = (NASpiSlaveBufferType *)buffer;
NaStatus ccode;

 // Do my stuff    
SLARMPACKET *pSP = (SLARMPACKET *)(spi_buffer-&gt;readBuffer);

SLARMData.UpdateSLARMPacket(pSP);

 // Refill the DMA pointer
spi_buffer-&gt;writeBuffer = gWriteData;
spi_buffer-&gt;readBuffer = gReadData;
spi_buffer-&gt;bufferLength = SPI_BUFFER_POOL_SIZE;
spi_buffer-&gt;bufferReturnFn = app_spi_raw_data_callback;

ccode = NASpiSlaveEnqueueBuffer(APP_SPI_SLAVE_PORT, spi_buffer);
if (ccode != NASTATUS_SUCCESS)
{
    printf("NASpiSlaveEnqueueBuffer() repost failed 0x%X

", ccode);
}
}

///////////////////////////////////

And here is the main:

///////////////////////////////////

extern “C”
void applicationStart (void)

{
NaStatus ccode;
NASpiSlaveBufferType naSSBT;
bool bSPIEnabled = false;

configure_gpio();

 // get the slave ready
ccode = NASpiSlaveInitialize(APP_SPI_SLAVE_PORT, 1, NA_SPI_MODE0, NA_SPI_MSB);
if (ccode != NASTATUS_SUCCESS)
{
    printf("NASpiSlaveInitialize() failed 0x%X: ", ccode);
    switch(ccode)
    {
   	case NASTATUS_SPI_SLAVE_INVALID_SETTINGS: printf("Invalid Parameters

"); break;
case NASTATUS_NOT_INITIALIZED: printf("Initialization Failed
"); break;
case NASTATUS_SPI_SLAVE_ACTIVE: printf("The slave driver already has been initialized for this port
“); break;
default: printf(”
"); break;
}
}
else
{
memset(&naSSBT, 0, sizeof(naSSBT));
memset(gWriteData, 0, SPI_BUFFER_POOL_SIZE);
memset(gReadData, 0, SPI_BUFFER_POOL_SIZE);
naSSBT.writeBuffer = gWriteData;
naSSBT.readBuffer = gReadData;
naSSBT.bufferLength = SPI_BUFFER_POOL_SIZE;
naSSBT.bufferReturnFn = app_spi_raw_data_callback;

	ccode = NASpiSlaveEnqueueBuffer(APP_SPI_SLAVE_PORT, &amp;naSSBT);
	if (ccode != NASTATUS_SUCCESS)
	{
	    printf("NASpiSlaveEnqueueBuffer() failed 0x%X

", ccode);
}
else
{
printf("SPI Enabled.
");
bSPIEnabled = true;
}
}

/* Initialize the system services for the application. */
initAppServices();

/*

  • Code to start the user application goes here.
    */
    printf ("Hello World. %s Ready
    ", APP_DIALOG_APP_NAME);

}

/////////////////////////////////////

I wish this forum didn’t strip tabs…

Thank you for posting the code.

My app works now as expected. I did the following (beginners) mistakes:

  • The callback function is called in interrupt context - printfs don’t work within this function.
  • Also breakpoints don’t work properly in the callback function. It stops execution but doesn’t show the code where it stopped.
  • I forget to enqueue a new buffer in the callback function.
  • The NASpiSlaveBufferType variable should not disappear (auto variable in a function that ends) because the SPI slave drive makes a copy by reference.

Thaks again and best regards,
mrib

Looking at the example, it seems that Digi is avoiding KISS again. Personally I would try your #2, but it seems you have some hacking ahead.

Good luck.

Hi here is my init code for the SPI. You will need to define more gSpiDevice structs for several slaves with different enable_cs and disable_cs functions. in thhis functions you can select any GPIO as slave select.

Jirka



 unsigned char gWriteData[SPI_BUFFER_POOL_SIZE * _POOL_OVERHEAD_SIZE];
 unsigned char gReadData[SPI_BUFFER_POOL_SIZE * _POOL_OVERHEAD_SIZE] __attribute__ ((aligned(32)));
 NASpiDeviceConfigType *devicePtr;



static __inline  void enable_cs(void)
{
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS,  NA_GPIO_OUTPUT_STATE, 0);      /*enable bit as GPIO output */
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC4_STATE, 0);
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_RXD, NA_GPIO_FUNC4_STATE, 0);
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_TXD, NA_GPIO_FUNC4_STATE, 0);
}


static __inline  void disable_cs(void)
{
	NAsetGPIOpin(APP_SPI_MASTER_GPIO_CS, 1);
}


static NASpiDeviceConfigType gSpiDevice = {
		APP_SPI_MASTER_PORT, 
        enable_cs, /*Callback function to select the SAPP_SPI_DEVICE Chip*/
		disable_cs, /*Callback function to deselect the SAPP_SPI_DEVICE Chip*/
		NA_SPI_MODE3, /*SPI mode, only mode 0 is supported in NS7520*/
		NA_SPI_MSB,   /*most significant bit first*/
		APP_SPI_DATA_RATE_1MBPS,  /* speed*/
		0, /* deselect time*/
		"SPI Master test"/*unique name for this device*/
};




/* 
 * Configure GPIO pins for SPIO master to work properly.
 * Each platform requires different setting of GPIO pins. 
 */
static void configure_gpio(void)
{
    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_FUNC4_STATE, 0);      
    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC4_STATE, 0);
    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_RXD, NA_GPIO_FUNC4_STATE, 0);
    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_TXD, NA_GPIO_FUNC4_STATE, 0);
}



int spi_test_master(void)
{
	
	NaStatus ccode = 0;
	
	
	devicePtr = &amp;gSpiDevice;
    configure_gpio();
    ccode = NASpiRegisterDevice(devicePtr);
    if (ccode)
    {
        printf("NASpiRegisterDevice() failed %d
", ccode);
        switch(ccode){
        	case NASTATUS_SPI_MASTER_DUPLICATE_DEVICE:
        		 printf("NASTATUS_SPI_MASTER_DUPLICATE_DEVICE 
");
        		 break;

        	case NASTATUS_RESOURCE_ERROR:
        		 printf("NASTATUS_RESOURCE_ERROR 
");
        		 break;        

        	case NASTATUS_SPI_MASTER_INVALID_SETTINGS:
        		 printf("NASTATUS_SPI_MASTER_INVALID_SETTINGS 
");
        		 break;
        		 
        	case NASTATUS_SUCCESS:
        		 printf("NASTATUS_SUCCESS 
");
        		 break;	 
        		 
        	default:
        		printf("neznama chyba 
");
        		 break;	
        		
        }
        return 1;
    }
    
	
	return 0;
}


The Digi Connect ME 9210 is aimed at OEMs who want to network-enable small-format industrial equipment, says Digi. Specific examples include programmable logic controllers (PLCs), power distribution units (PDUs), and building environment controls.

Digi calls the new Connect ME module “interchangeable” with older Connect ME products, which share the same dimensions and pin-out on the 20-pin interface that connects the module to the host system.

Cheap SEO

Thanks for posting the multiple SPI slave example, the code looks very reasonable. I’m going to run the 1st PCB with multiple chip selects (option#2) and as soon as the copper comes in, I’ll give it a try.

Thanks Again!