Spider & try to use Socket 9 (and reading it's analog values)

Using this as my reference - http://www.ghielectronics.com/downloads/Gadgeteer/Mainboard/Spider/FEZ%20Spider%20Schematics.pdf

I want to use Socket 9 pins 3 & 4 as GPIO, and 5 for Analog reading.

Is this correct?

  • Pin 3 = GPIO 46
  • Pin 4 = GPIO 6

For analog input:

  • Pin 5 = AD 3

I was able to use these pins just fine in managed code. But in my ported code, it doesn’t seem to be returning any values – generalArray is full of 0.

So I simplified my code to the most basic to just read the analog values. I’m feeding the analog pin the output from my iPhone - P5 to the tip and GND to the sleeve. I’m still getting just 0s.

To ensure that data is being passed between managed & RLP, I changed assignment to: generalArray[i] = i; and in managed, it’s showing 0 thru 7.

So I’m missing something here (no surprise ;))

(based on the code here: GHI Electronics – Where Hardware Meets Software)


int GHAL_AnalogIn_Read(unsigned char channel)
{
    return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >> 8) & 0x3FF;
}

int GetReadings(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	int i;
	for (i = 0; i < 7; i++)
	{
		RLPext->Delay(10);
		// read the analog value		
		generalArray[i] = GHAL_AnalogIn_Read(3);		
	}
	return 0;
}

In managed:


var intArray = new int[7];
var result = GetReadings.InvokeEx(intArray);

The pointer to the array is in args[0]

I’ll give that a try … but when I did this:

generalArray[i] = i;

my array in C# world had 0,1,2,3,4,5,6.

FWIW - I was working from this:
http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation/html/f608e398-6573-8adc-5d59-b904dfa3fcee.htm

and this code sample:


// C#: Foo7.InvokeEx(intArray, byteArray);     // uses a generalArray (intArray) // one variable argument (byteArray)
int Foo7(int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
    // argsCount == 1
    // argSize[0] == 10
    unsigned char *byteArray = (unsigned char*)args[0];    // same byteArray in C#
    // generalArray is the same as intArray in C#

    return 0;    // Some return value
}


         int *intArray = (int*)args[0];

	int i;
	for (i = 0; i < 7; i++)
	{
		RLPext->Delay(10);
		// read the analog value		
		intArray[i] = GHAL_AnalogIn_Read(3);		
	}
	return 0;

Still gives zeros. If I change the managed to:

var result = GetReadings.Invoke(intArray);

I get an exception “Argument (0) is not supported”

You need to configure the PIN for AD input, configure the AD clock, and many more :slight_smile:
Then you need to start AD conversion and wait for ADC_DONE flag before each read.

Download “Sample Code Bundle for LPC23xx/LPC24xx Peripherals using Keil’s μVision” from http://ics.nxp.com/support/documents/microcontrollers/?type=software
and check out the ADC sample.

Here some extracted code:


DWORD ADCInit( DWORD ADC_Clk )
{
  /* Enable CLOCK into ADC controller */
  PCONP |= (1 << 12);

  /* all the related pins are set to ADC inputs, AD0.0~7 */
  PINSEL0 |= 0x0F000000;	/* P0.12~13, A0.6~7, function 11 */	
  PINSEL1 &= ~0x003FC000;	/* P0.23~26, A0.0~3, function 01 */
  PINSEL1 |= 0x00154000;
  PINSEL3 |= 0xF0000000;	/* P1.30~31, A0.4~5, function 11 */

  AD0CR = ( 0x01 << 0 ) | 	/* SEL=1,select channel 0~7 on ADC0 */
		( ( Fpclk / ADC_Clk - 1 ) << 8 ) |  /* CLKDIV = Fpclk / 1000000 - 1 */ 
		( 0 << 16 ) | 		/* BURST = 0, no BURST, software controlled */
		( 0 << 17 ) |  		/* CLKS = 0, 11 clocks/10 bits */
		( 1 << 21 ) |  		/* PDN = 1, normal operation */
		( 0 << 22 ) |  		/* TEST1:0 = 00 */
		( 0 << 24 ) |  		/* START = 0 A/D conversion stops */
		( 0 << 27 );		/* EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion) */ 

  return (TRUE);
}

DWORD ADC0Read( BYTE channelNum )
{
 #if !ADC_INTERRUPT_FLAG
  DWORD regVal, ADC_Data;
 #endif

  /* channel number is 0 through 7 */
  if ( channelNum >= ADC_NUM )
  {
	channelNum = 0;		/* reset channel number to 0 */
  }
  AD0CR &= 0xFFFFFF00;
  AD0CR |= (1 << 24) | (1 << channelNum);	
				/* switch channel,start A/D convert */
 while ( 1 )			/* wait until end of A/D convert */
  {
	regVal = *(volatile unsigned long *)(AD0_BASE_ADDR 
			+ ADC_OFFSET + ADC_INDEX * channelNum);
	/* read result of A/D conversion */
	if ( regVal & ADC_DONE )
	{
	  break;
	}
  }	
        
  AD0CR &= 0xF8FFFFFF;	/* stop ADC now */    
  if ( regVal & ADC_OVERRUN )	/* save data when it's not overrun, otherwise, return zero */
  {
	return ( 0 );
  }
  ADC_Data = ( regVal >> 6 ) & 0x3FF;
  return ( ADC_Data );	/* return A/D conversion value */
}


EDIT: Ooops, I just see that the example creates a managed AnalogIn object which should do the initialization for you, so make sure you also create a managed AnalogIn object.

OK – maybe I am way too far over my head then.

I was looking at a few samples and they just seemed to read pin.

For example:

#define ADC_DATA_BASE_ADDRESS 0xE0034010
 #define RLP_ADDRESS		0xA0F00000 //for EMX
 #define RLP_SIZE		0x000FFFFC //for EMX
int GHAL_AnalogIn_Read(unsigned char channel)
{
        return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >>8) & 0x3FF;
}
int ReadAudio(unsigned int *generalArray, void **args, unsigned int argsCount , 
              unsigned int *argSize)
{
        unsigned char *buffer = (unsigned char*)args[0];
        int buffer_lengh = argSize[0];
        unsigned char channel = *(unsigned char*)args[1];
        int i=0;
        while(i<buffer_lengh)
        {
           buffer[i] = GHAL_AnalogIn_Read(channel);
           i++;
           RLPext->Delay(125);
        }
        return 0;
}

.. IN MANAGED ...

static RLP.Procedure ReadAudio;
static byte[] dataRPLWave = new byte[4*8000]; // time length of wav file
static void RecordWAV(AnalogIn.Pin channel, byte[] data)
        {
            AnalogIn ain = new AnalogIn(channel);
            ReadAudio.Invoke(data, (byte)(channel));
            ain.Dispose();
        }

Is this line in managed doing all the things you were mentioning in your post?
AnalogIn ain = new AnalogIn(channel);

** edit – looks like we came to same conclusion :slight_smile:

In the sample code for reading audio, this part is completely foreign to me, as I’ve never worked with bit manipulations in the past:


        return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >>8) & 0x3FF;

specifically this part: >> 8 & 0x3FF;

Also, an Analog reading, I thought, was between 0 and 3.3V. How is this converted to a byte? Is it just 0 thru 33?

**

With your and others assistance, I feel like I am getting close to getting it to work – not really fully understanding it, but chipping a bit off the top of the iceberg :wink:

Right shift with 8 is the same as dividing by 256. In essence, this means that the value starts at bit 9, so you shift away the lower 8 bits. Next is a mask of 0x3ff, that only keeps the lower 10 bits.

So the RLP version is working (sorta), but is is getting a lot of “phantom” readings.

I have an WPF app that generates the different tones my chip will read back the levels to me - using the analog in. My computer is connected to the device via head phone jack, so you won’t hear anything in the video. I’m turning on the 4th frequency in the various videos.

This is the managed version of the code.

This is the RLP version. You can see the bar is indicating the frequency being generated, but the other bars are providing a bunch of phantom reading.

And here are the values coming back from RLP to managed. At this time, the audio is off. You can see the values are all over the place.

Within the managed version I construct me AnalogIn like this:


InputPin = new GTI.AnalogInput(sock, GT.Socket.Pin.Five, null);

In the managed code, using the RLP for reading, I use this instead (using the Gadgeteer version results in nothing Zeros in the array):


AnalogIn ain = new AnalogIn(AnalogIn.Pin.Ain3);

Yes, you’re assuming Ain3 == channel3:

GHAL_AnalogIn_Read(3);

Which will not be the case. You will need to test other channels in RLP until you find the right one.

Ok - ill give it a try later on. In the second video, you could see that it seemed that it was reacting to the frequency, so I assumed it was the correct.

Do you suggest that I try all 7 ADC channels? Or is there a way to see which ADC I’m using? According to the GHI datasheet, Socket 9, Pin 5 is AD3.

Thanks again for the help.

Videos fixed.

@ mhectorgato - I would try all 7 :slight_smile:

I tried to instantiate all ADC ports in my managed code. The ones commented out are ones that threw an exception.


// AnalogIn ain0 = new AnalogIn(AnalogIn.Pin.Ain0); // S10; P5 (touch?)
// AnalogIn ain1 = new AnalogIn(AnalogIn.Pin.Ain1); // S10; P4 (touch?)
AnalogIn ain2 = new AnalogIn(AnalogIn.Pin.Ain2); // S9; P4 
AnalogIn ain3 = new AnalogIn(AnalogIn.Pin.Ain3); // S9; P5                             
// AnalogIn.Pin.Ain4 // does not exist
// AnalogIn ain5 = new AnalogIn(AnalogIn.Pin.Ain5); // GREEN LED 
AnalogIn ain6 = new AnalogIn(AnalogIn.Pin.Ain6); // S10; P3
AnalogIn ain7 = new AnalogIn(AnalogIn.Pin.Ain7); // S9; P3                               

I commented all of the working ones, and brought one back in at a time.

Ain2 = no readings
Ain3 = original pin (readings all over the place)
Ain6 = no readings
Ain7 = no readings

Ok so ADC port number seems to match right? But you’re measuring noise.

Can you show the latest RLP code you’re using now?

// You might need to change this depending on the location of the header file
 #include <RLP.h>
 #define RLP_ADDRESS		0xA0F00000
 #define RLP_SIZE		0x000FFFFC

 #define ADC_DATA_BASE_ADDRESS 0xE0034010

 #define LCD_BASE_ADDR		0xFFE10000
 #define LCD_UPBASE   		(*(volatile unsigned long *)(LCD_BASE_ADDR + 0x0010)) // this define reads out the value from the LCD_UPBASE address

int ResetPin;
int StrobePin;
unsigned short * pixelMap;

// set pins
int Init(unsigned int *generalArray, void **args, unsigned int argsCount,
              unsigned int *argSize)
{
	ResetPin = 46; // Socket 9 Pin 3 
	StrobePin = 6; // Socket 9 Pin 4

	// config the GPIO pins
	RLPext->GPIO.EnableOutputMode(ResetPin, RLP_GPIO_RESISTOR_DISABLED);
	RLPext->GPIO.WritePin(ResetPin, RLP_FALSE);   
	
	RLPext->GPIO.EnableOutputMode(StrobePin, RLP_GPIO_RESISTOR_DISABLED);
	RLPext->GPIO.WritePin(StrobePin, RLP_TRUE);   

	pixelMap = (unsigned short *)LCD_UPBASE;
	
	// init the chip
	RLPext->GPIO.WritePin(ResetPin, RLP_TRUE);   
	RLPext->Delay(5);
	RLPext->GPIO.WritePin(ResetPin, RLP_FALSE); 
	
	return 0;
}

int GHAL_AnalogIn_Read(unsigned char channel)
{
	return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) ) & 0x3FF; // get 10-bit value; 0-1023
}
int ReadAudio(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{				
	int i=0;
	for (i =0; i< 7; i++)
	{
		// prep for read
		RLPext->GPIO.WritePin(StrobePin, RLP_FALSE);   
		// allow to settle
		RLPext->Delay(30);
		// read the analog value		
		generalArray[i] = GHAL_AnalogIn_Read(3);			
		// set the pin for the next frequency
		RLPext->GPIO.WritePin(StrobePin, RLP_TRUE);   			
	}
	return 0;
}

Managed code:


                int[] dataRPLWave = new int[7];

                while (true)
                {
                    Thread.Sleep(50);
                    ReadAudio.InvokeEx(dataRPLWave, (byte)3);

                    for (int i = 0; i < 7; i++) 
                    {
                        if (dataRPLWave[i] > 0 && dataRPLWave[i] < max)
                            movingAvergage[i].AddValue((int)((dataRPLWave[i] / max) * max));
                        else
                            movingAvergage[i].AddValue(0);
                    }
                    eq.UpateDisplay(false, false);
                }

Try to replace your read function with this one:


 #define ADC_DONE 0x80000000

int GHAL_AnalogIn_Read(unsigned char channel)
{
    volatile unsigned long* reg = (volatile unsigned long*)ADC_DATA_BASE_ADDRESS;
    reg += channel;
    unsigned long val;
    while (((val = *reg) & ADC_DONE) == 0) {} // wait until AD conversion is ready
    return (int)((val >> 6) & 0x3FF);
}

It waits until the DONE flag is set which means you’ll get a valid read, if you don’t do that you can get wrong values.

1 Like

Thanks - much better!

I have some fine tuning to do still – but thanks so much :slight_smile:

Once I get it worked out, I’ll put it up on Codeshare.