UBW32 and MicroMag3 working code..

Have you got the greatest 48 bit multiplier ever conceived? Prove it - post your code here.

Moderator: phalanx

Post Reply
jondaeh
Posts: 31
Joined: Thu Feb 19, 2009 12:56 am
Location: Ålesund, Norway

UBW32 and MicroMag3 working code..

Post by jondaeh » Tue Feb 02, 2010 12:57 pm

It took a little time to make everything work, so I'm posting it here if anyone should be interested.

This C32 code makes the UBW read the magnetometer with bitbanging, and outputs it through the UART1 port. Then it can easely be read with a PC with a serialport.

For reference, I took some inspiration from this code, which is for Arduino(I think):
http://cwwang.com/2008/02/20/micromag-3-axis/

This is how I connected it:
Micromag - PIC32
pin1 - D6 (Serial clock, output)
pin2 - D13 (MISO)
pin3 - D12 (MOSI)
pin4 - D3 (Slave select, output)
pin5 - D2 (Data ready, input)
pin6 - D1 (Reset, output)

I'm powering the magnetometer from the 3,3V pin on the UBW, and the UBW is powered from the USB connector.

If you are just looking for the code that reads the magnetometer in particular, it is the readMagneto(), getBit() and sendBit(int) functions that is the most important ones.

If you got any questions or comments, feel free to PM me :D

Code: Select all

#include <p32xxxx.h>
#include <stdio.h>

/*Prototypes*/
int main(void);
int readMagneto(int);
void transmit(char*, int);
void init(void);
char *intToChar(signed int, int);
void sendBit(int data);
short getBit(void);
void wait(int);


//D6  (Serial clock, output)
//D13 (MISO)		
//D12 (MOSI)
//D3  (Slave select, output)
//D2  (Data ready, input)
//D1  (Reset, output)

static char charBuff[7];      //To be able to send an array between functions
enum axis { X = 1 , Y , Z };  //Defines X-axis as 1, up to Z-axis as 3.



int main()
{
init();
char c[9] = {'I', 'n', 'i', 't', ' ', 'O', 'K', '!', ' '}; 
transmit(&c[0], 7); //Just to clarify that that the PIC32 is going.


//The for loop starts with the X-axis, and iterates up to the Z-axis. 
//The while loop makes shure is does this forever.
while(1)
{
	int iterate;
	for(iterate = X;iterate <= Z;iterate++) 
	{	
		//Get a reading on the axis hold by iterate
		signed int axisRead = readMagneto(iterate); 
		
		//Convert it to an char array, and put the name of the axis in front
		char *xptr = intToChar(axisRead, iterate);	
		
		//Send it to the computer with serial
		transmit(xptr,7);				            
		wait(65000);
	}
}
return 0;//Unreachable..
}

/*Returns the reading for the X-axis*/
signed int readMagneto(int readRef)
{
	short sign;     
	short rawValue;
	int iterate;
	signed int result;
	
	
	PORTDbits.RD3 = 0; //SSNOT low
	//Wait at least 100 nano seconds. This is more.
	wait(100);
	PORTDbits.RD1 = 1; //Reset high	
	wait(100);		   	
	PORTDbits.RD1 = 0; //Reset low
	wait(100);
	//Send a command for to the MicroMag. period /2048. Highest value that guarantees no overflowing.
	sendBit(0);
	sendBit(1);
	sendBit(1);
	sendBit(0);
	sendBit(0);
	sendBit(0);
	
	//The last two bits decides which axis to read. 
	//readRef holds the enum of which axis this is.
	switch (readRef)
	{
		case X:
		{
			sendBit(0);
			sendBit(1);
			break;
		}
		case Y:
		{
			sendBit(1);
			sendBit(0);
			break;
		}
		case Z:
		{
			sendBit(1);
			sendBit(1);
			break;
		}
	}
	
	while(!PORTDbits.RD2); //Wait for data ready signal from the magnetometer
	
	sign = getBit(); 	//Get the first bit, this is the "sign" if it is a negative number or not.
	rawValue = getBit();//Get the next bit
	for(iterate = 0; iterate < 14 ;iterate++)//And the last 14 bits.
	{
			rawValue <<= 1;   //Shift the bits in rawValue one to the left
			
			//Bitwise OR what's in rawValue and the next bit from the 
			//magnetometer together. Add them would probably also work..
			rawValue = rawValue | getBit();	
	}
	PORTDbits.RD3 = 1; //Bring SSNOT high
	//MicroMag3 returns a 2's complement, ranging from -32768 to +32767. 
	//"Sign" keeps the sign of the signed integer.
	//If Sign == 1 then it's a negative number, then subtract 32768 from the value to get it right.
	if(sign)
	{
		result = rawValue - 32768;
	}
	else
	{
		result = rawValue;
	}
	
	return result; //return the final result as a signed integer.
}

/*Sends the int through the UART*/
void transmit(char *c, int l)
{
	//Iterates through the array pointed to by c. If UART1 sendbuffer is full, wait til it's empty.
	int i;
	U1TXREG = ' '; //Put in a space to separate the values
	for(i = 0; i < l; i++)
	{ 
		while(U1STAbits.UTXBF);
		U1TXREG = *(c + i);  
	}
	
}



char *intToChar(signed int i, int axis)
{
	//Putting the name of the axis in front of the reading.
	switch(axis)
	{
		case X: 
		{
			charBuff[0] = 'X';
			break;
		}
		case Y: 
		{
			charBuff[0] = 'Y';
			break;
		}
		case Z: 
		{
			charBuff[0] = 'Z';
			break;
		}
		default:{break;};
	}
	
	charBuff[1] = ':';
	
	//Makes an array of the integer i, and puts the first char in 
	//posistion 2 in the array, after the name of the axis.
	sprintf(&charBuff[2], "%d", i); 
	return &charBuff[0]; //Returns a pointer to the array just "refilled".
}


void sendBit(int data)
{
	//Clocks in 1 bit TO the magnetometer.
	//As the Pic32 runs at 80Mhz, put 40 cycles between easch line here, 
	//should get the MicroMag well away from the 1Mhz limit.
	PORTDbits.RD12 = data; //Putting the data we want to send to the magnetometer
	wait(40);
	PORTDbits.RD6 = 1;	//Clock high
	wait(40);
	PORTDbits.RD6 = 0;	//Clock low
	wait(40);
}

short getBit(void)
{
	//Clocks and reads one bit from the magnetometer.
	PORTDbits.RD6 = 1;//Clock high
	wait(40);
	short data = PORTDbits.RD13; //Reading what the magnetometer has to say
	wait(40);
	PORTDbits.RD6 = 0;	//Clock low
	wait(40);
	return data;	//Returns one bit(a short that's 1 or 0).
}

void wait(int cycles)
{
	//Only wait for the given number of cycles. 
	TMR1 = 0;
	while(TMR1 < cycles);
}

void init()
{
	//Initializes the PIC32 with the desired I/O's, 
	//and sets up the UART1 serial port. 
	
	//I/O's
	TRISDbits.TRISD1 = 0;
	TRISDbits.TRISD2 = 1;
	TRISDbits.TRISD3 = 0;
	TRISDbits.TRISD6 = 0;
	TRISDbits.TRISD12 = 0;
	TRISDbits.TRISD13 = 1;
	TRISFbits.TRISF1 = 0;
	
	//Sets appropiate initial states of the outputs
	PORTDbits.RD1 = 0; //Reset
	PORTDbits.RD3 = 1; //Slave Select
	PORTDbits.RD6 = 0; //SPI Clock
	PORTDbits.RD12 = 0;//MOSI
	
	U1MODE = 0x8008;
	U1STA = 0x400;
	U1BRG = 2082; //Sets baud=4800
	
	T1CON = 0x8030;//Sets up the timer
}

Cheers.

Jon
Norway

magneto36
Posts: 2
Joined: Sat Feb 12, 2011 10:49 am

Re: UBW32 and MicroMag3 working code..

Post by magneto36 » Sat Feb 12, 2011 10:57 am

Hi..Thank you for the code. I have this question on how can you make pic32 communicate with micromag3-axis magnetometer and store the those values on a SD card which is mounted on pic32. i am having trouble with the pic32 as this is my first time using it. it would be great if you can push me in the right direction with providing some incite towards the code or with some sample code. and in the code you have provided which i/o pin section did you use, by that i mean did you use j4 or j2 or j10 i/o pin configuration. Reply as soon as you can .
Thanks

jondaeh
Posts: 31
Joined: Thu Feb 19, 2009 12:56 am
Location: Ålesund, Norway

Re: UBW32 and MicroMag3 working code..

Post by jondaeh » Mon Feb 14, 2011 1:02 am

Hi magneto36!

My best suggestion to get going on programming PIC32 with C32, is to read his book:
http://www.amazon.com/Programming-32-bi ... 0750687096

It helped me a lot, as the C32 is a bit hard to find basic documentation for. I think the book also covers some flash-memory operations.

However, if there is something particular you need help for, just ask.
You mentioned:
and in the code you have provided which i/o pin section did you use, by that i mean did you use j4 or j2 or j10 i/o pin configuration.
I'm not sure if I understand what you ask for. In the code I have commented

Code: Select all

/D6  (Serial clock, output)
//D13 (MISO)      
//D12 (MOSI)
//D3  (Slave select, output)
//D2  (Data ready, input)
//D1  (Reset, output)
So I'm using the D-section, if that's what you mean.

Please ask me again if I missunderstood you, I'm happy to help you!


Jon, Norway

magneto36
Posts: 2
Joined: Sat Feb 12, 2011 10:49 am

Re: UBW32 and MicroMag3 working code..

Post by magneto36 » Sun Feb 20, 2011 7:50 pm

Thank you for the reply. Your code worked but could you help me on how would you interpret the data coming out of the magnetometer for X,Z, and Y axis. By that i mean when the magnetometer is flat on the surface i get -1 for two axis and some other big number for the third axis and i can't figure out how to interpret them. The range of the magnetometer is +/- 11 gauss.
Could you tell me how to interpret the data i am getting from the code you provided. Could you be specific like if i am getting
-23000 as one of the number what does that mean, and the unit for the data. Your help is much appreciated.

Thank you
Magneto36

jondaeh
Posts: 31
Joined: Thu Feb 19, 2009 12:56 am
Location: Ålesund, Norway

Re: UBW32 and MicroMag3 working code..

Post by jondaeh » Tue Mar 01, 2011 1:29 am

Alright, now I understand your question!

Honestly, I don't know exactly what you get out of the magnetometer. However, I assume it is a measurement for the magnetic force in respective axis. Big number means the axis on the magnetometer is good aligned with the magnetic force. What the unit is I am not sure of either, but gauss seems magnetic:P

What you probably want to do, like me, is to use it for absolute orientation in roll, yaw and pitch. Well, I never succeeded with this, and migrated to a gyro-accelerometer combo.

Hope this is some sort of help, I just implemented the magnetometer, I haven't used it for anything useful yet..;)

Jon, Norway

Post Reply