HMC5883L I2C library for 32-bit ARM STM32f103xx family

On the way to develop my MARG system which has MPU6050 & HMC5883L, I finished writing a I2C library for HMC5883L for 32-bit ARM STM32F103xx family of microcontrollers. It has been tested on Olimex STM32-P103 development board. This library depends on only two header files from STM32F10xFWLib v3.3.0:

stm32f10x.h
stm32f10x_i2c.h

Here is few lines of code showing how to use this library:

#include "HMC5883L.h"
HMC5883L_I2C_Init();
HMC5883L_Initialize();
if( HMC5883L_TestConnection());
{
   // connection success
}else
{
   // connection failed
}

int16_t  MagneticHeading[3]={0};
HMC5883L_GetHeading(MagneticHeading);

As you can see, these are the minimum number of function calls to get the measurements from HMC5883L. To access all the registers of HMC5883L, see the source files.
Doxygen html documentation will be available soon. For the library source files & updates visit : GitHub HMC5883L Repository
If you find any bugs or want to improve & have any suggestions. You are always welcome.
Note: At present this library is working successfully on STM32F103RB with sparkfun HMC5883L breakout board. It should work on other microcontrollers of same family too. The breakout board is connected to I2C2 of STM32-P103 Olimex board.

MPU6050 I2C library for 32-bit ARM STM32f103xx family

On the way to develop my MARG system which has MPU6050 & HMC5883L, I finished writing a I2C library for MPU6050 for 32-bit ARM STM32F103xx family of microcontrollers. It has been tested on Olimex STM32-P103 development board. This library depends on only two header files from STM32F10xFWLib v3.3.0:

stm32f10x.h
stm32f10x_i2c.h

Here is few lines of code showing how to use this library:

#include "MPU6050.h"
MPU6050_I2C_Init();
MPU6050_Initialize();
if( MPU6050_TestConnection()== TRUE);
{
   // connection success
}else
{
   // connection failed
}

int16_t  AccelGyro[6]={0};
MPU6050_GetRawAccelGyro(AccelGyro);

As you can see, these are the minimum number of function calls to get the acceleration, angular rate from MPU6050. To access all the registers of MPU6050, see the source files.
Doxygen html documentation will come soon. For the library source files & updates visit : GitHub MPU6050 Repository
If you find any bugs or want to improve & have any suggestions. You are always welcome, please leave a message.
Note: At present this library is working successfully on STM32F103RB with sparkfun MPU6050 breakout board. It should work on other microcontrollers of same family too. The connection diagram can be seen in other posts in my blog.

MPU6050 development on ARM STM32f103RB

A month ago i started working on developing a device using MEMS motion sensors with the following features:

  • AHRS( Attitude and Heading Reference System) for 3D rotation( Quaternion, Euler angles& Rotation matrix)
  • Raw & calibrated sensor measurements
  • Powerful 72MHz ARM Microcontroller STM32F103xB (Later STM32F103xE)
  • Using FreeRTOS
  • DFU(Device Firmware Upgrade) capability
  • Sensors: at present MPU6050, HMC5883L
  • Communication: USB 2.0 & Bluetooth

I have Olimex STM32-P103 bord which has STM32F103RBT6 micro. So far i finished

  • USB CDC Class Virtual Com port driver.
  • Streaming data to UART Bluetooth module.
  • MPU6050 I2C has been tested ( need to improve & optimize ).

I was testing my I2C code, It took too much time. Unfortunately It was very hard to figure out what was happening to my I2C code written for MPU6050 with the old oscilloscope i’m using could not help me to solve. After posting my problem in ST Forum, a few people suggested after days. Meanwhile i started testing my MPU6050 breakout board from Sparkfun on Arduino pro mini. Initially it didn’t work. I communicated with Jeff( a nice guy). I desoldered & soldered the connections, checked for continuity, voltage levels etc. It worked finally. So, now after making sure I’m back onto my Olimex STM32-P103 board to test I2C code. No luck.  After digging out, I fixed it. It was the 7-bit address problem. MPU6050 I2C address is 0×68. But in STM32, i have to use the 1-bit left shifted address(0xD0) of this.

Below is the connection diagram.

I’m working on MPU6050 I2C optimized library development for ARM STM32F103x.

What is the future of machine intelligence ?

Today I passed by a computer scientist web page who constructed his own computer using relays with 32k memory chip. He has written an article “Warnings of dark future: The emergence of Machine Intelligence“. I felt its worth sharing  and here is the link to his website: http://web.cecs.pdx.edu/~harry/musings/DarkFuture.html
He answers the question Can’t We Just Turn the Robots Off?

Here is the video of his own computer :

A page with links to over 60 videos, each showing a different interesting or unusual robot, showcasing the diversity of contemporary robotic and bionic technology.

http://web.cecs.pdx.edu/~harry/Robots/index.html

It is a fact that at some point in the future, a single computer will have more processing power than a human brain. The only real question is whether this will occur in 10 years, in 20 years, or later. Based on Moore’s law, he (I’m too) predict that in 15 years the raw computation power of some computers will exceed that of the human brain. Barring an event like World War III, this milestone will almost certainly be reached before you are 30 years older than you are now.

OpenGL Inverse Transformations without 4×4 matrix Inverse

In graphics applications, transformations and their inverse transforms are frequent mathematical operations. There are three transformations Translation, Rotation and Scaling. People may choose different mathematical approaches to do transformations, for example, for rotation 3×3 Rotation matrix, quaternion. Vectors for translation & scaling .

Whatever the format used to represent spatial transformations, the ultimate goal is to achieve the required transformations with minimum computational operations & which should be numerically stable. Many people use matrices for spatial transformations regardless of graphics API ( Ex: OpenGL, DirectX etc..).

After working on navigation algorithms & graphical visualization, I found it is not a good idea to use matrices for representing spatial transformations.  I like Quaternion representation of rotation other than any. The beauty of Quaternions lies in

  • Compact representation q={q1, q2, q3, q4}
  • Inverse too simple
  • Numerically stable
  • No gimbal lock problem

I guess I’m writing too much about Quaternions. Now i will jump to what you are looking for.  OpenGl modelVeiw matrix is a 4×4 matrix which contains all the spatial transforms applied. If you want to take inverse of this matrix, it is very tedious & may be numerically unstable. See the 4×4 matrix Inverse c++ code: Matrix Inverse

You must be tired after seeing matrix inverse code. Lets look at the below simple code to achieve the same. But, at present the following code works only when there was no Scaling transform applied. However this is useful in many applications, for example, in forward/inverse kinematics.

void MatrixInverse(float OpenGLmatIn[16], float matOut[4][4])
{
    float matIn[4][4];
    // OpenGL matrix is column major matrix in 1x16 array. Convert it to row major 4x4 matrix
    for(int m=0, k=0; m<=3, k<16; m++)
      for(int n=0;n<=3;n++)
      {
        matIn[m][n] = OpenGLmatIn[k];
        k++;
      }
    // 3x3 rotation Matrix Transpose ( it is equal to invering rotations) . Since rotation matrix is anti-symmetric matrix, transpose is equal to Inverse.
    for(int i=0 ; i<3; i++){
    for(int j=0; j<3; j++){
      matOut[j][i] = matIn[i][j];
     }
    }
    // Negate the translations ( equal to inversing translations)
    float vTmp[3];

    vTmp[0] = -matIn[3][0];
    vTmp[1] = -matIn[3][1];
    vTmp[2] = -matIn[3][2];
    // Roatate this vector using the above newly constructed rotation matrix
    matOut[3][0] = vTmp[0]*matOut[0][0] + vTmp[1]*matOut[1][0] + vTmp[2]*matOut[2][0];
    matOut[3][1] = vTmp[0]*matOut[0][1] + vTmp[1]*matOut[1][1] + vTmp[2]*matOut[2][1];
    matOut[3][2] = vTmp[0]*matOut[0][2] + vTmp[1]*matOut[1][2] + vTmp[2]*matOut[2][2];

    // Take care of the unused part of the OpenGL 4x4 matrix
    matOut[0][3] = matOut[1][3] = matOut[2][3] = 0.0f;
    matOut[3][3] = 1.0f;
}

I would like to extend this even for the scaling transformation also. If someone comes with that, it would be very good. Hope you enjoyed reading this. If you find this useful or need any help understanding the math behind, I’m happy to answer you.

Virtual Com Port for Olimex STM32-P103 + IAR EW + FreeRTOS + Windows 7

I’m stuck with a problem. Started writing this post with hope anyone over web could suggest something.

I have Olimex STM32-P103 bord which has STM32F103RBT6 micro. I flashed Virtual com port DEMO code .hex file from the example code they provided. It could not install the driver on windows 7( shows failure message after searching). It’s because they provided driver for windows XP only. After 3 emails to Olimex support, they responded & provided support to make windows 7 driver. Now i have windows 7 driver working with their example code. However, This example uses old libraries and no FreeRTOS. This sample uses CBR_9600 baudrate. Also this code doesn’t support DFU mode because it is programmed in flash at base adress 0×08000000. Also, i prefer to implement my application using FreeRTOS .

I also have STEVAL-MKI062V2 iNEMO v2 with micro STM32F103RET7. ST provided Firmware project source for IAR Embedded workbench. It has USB virtual com port code with DFU support. I want to utilize this code to make STM32-P103 board communicate via virtual COM port with DFU support. I’m working with IAR EW+FreeRTOS+ST-LINK+WINDOWS 7.

The default boot mode for Olimex board is FLASH memory.

In adapting the iNEMO v2 code for Olimex board, i did the following.

For DFU support :

Created a project & configured it to suit medium density devices in Linker option config file. Olimex board user push_button configured to enter DFU mode. Compiled the iNEMO_DFU project code, flashed the iNEMO_DFU.hex in FLASH at base adress 0×08000000. Option byte also configured.

For USB Virtual Com Port application:

1. Created a project & configured it to suit medium density devices in Linker option config file. Also modified Startup_stm32f10xmd.s file to suit in FreeRTOS environment as below:

EXTERN __iar_program_start
EXTERN SystemInit
EXTERN vPortSVCHandler ; defined for FreeRTOS
EXTERN xPortPendSVHandler ; defined for FreeRTOS
EXTERN xPortSysTickHandler ; defined for FreeRTOS

PUBLIC __vector_table

2. Configured DISC, push button & status LED pin of Olimex board to suit iNEMO board DISCONNECT pin of USB & push button(sw2), status LED buttons.
3. I did not change any descriptors related to USB in the Virtual com port code of iNEMO.

When i DEBUG & see, the debugger stuck in the while loop shown in the code below. which means something is wrong in USB related things( i guess clock configuration & driver related). Any code wrote before the while loop works fine.

void inInitTask(void *pvParameters)
{
    iNEMO_HW_Config(); //Configure the hardware for the iNEMO platform
    while(bDeviceState != CONFIGURED); // THIS LOOP IS GOING INFINITE
    iNEMO_Config(); // Initialize the iNEMO sensor platform
    Timer_Config(); // Configures the timer 2 for frequency interrupts in Hz
}

If i do step by step debugging inside iNEMO_USB_Disconnect_Pin_Config() computer shows the message “Unknown Device” as shown in images.

If i don’t do step by step debug, it goes to that while loop & sits there, never comes out of that . If i reset the device, It is not running the code which i flashed starting from address 0×08003000.

i. I don’t understand why the device not running the application code when i reset the device. I’m saying this because the user LED is not glowing.

ii. I’m quite sure that the “Unknown Device” problem is related to clock configuration & driver. How do i configure the clock ?

How to use the driver inemo folder so that Olimex board can be recognized by computer.

Recently i found SystemInit( ) function differs from Olimex sample. SO replaced it with Clk_Init( ) from example code. No use, still it stuck in the while loop.

Code in WordPress.com Blogs using HTML paste from Visual studio 2010

To put some code into blog posts, we need syntax highlighter. These syntax highlighters comes as plugins for blogs. Some blogs may not have option for plugins. I explain a way how to do this without need of plugins. WordPress.com blogs has two options to write posts, visual editor & HTML editor. I use HTML editing & visual editing simultaneously when i have to put some code into post. Many people may not be aware of HTML coding. But there is a way to get HTML code by just copying your code & paste it to an HTML file. To do this we need get productivity power tools of Visual studio 2010. It is easy to install it from visual studio 2010 : go to Tool->Extension Manager->Online Gallery . Restart the visual studio, open your file where you have your code. Now open a new HTML file. Now  don’t afraid by seeing the default code in HTML file. Just copy the your code from your code file and go to HTML file, place cursor as shown in figure. Go to Edit-> Paste Alternate. Now you can see HTML code, which has come from ‘Paste Alternate‘ . At the bottom of the HTML file, you can see Design   Split   Source . Click on Split, you will see a new window where you can see the actual code. Save the HTML file and right click on the HTML code, select View in Browser. You are done. Now, we need to paste part of this HTML code into WordPress.com blog such as mine. Switch to HTML editor of your WordPress.com post, paste the part of the code shown in last image. Now, you can switch to visual editor and edit the text as you wish. But I’m unaware of formatting things as they change after HTML code. If you are good at HTML coding, it may be easy. You will see the following lines in your post after you publish.

public class Class1
{
     public Class1()
     {
       int myvar;
     }
}

iNEMO v2 with ST-LINK and IAR Embedded Workbench: Part 2

Set up to connect iNEMO v2 to PC as well as to Bluetooth module  is shown in image. For wireless transmission of data packets to PC, I programmed iNEMO board. Bluetooth module connected to USART2 of STM32. I wrote interrupt service routine which puts the data packet into the Data register(DR). I used TXE bit to trigger the interrupt. This interrupt is enabled after the data packet is sent to USB. Now I’m able to receive data packets in both the ways. Receiving control data packets & acknowledgement is in progress. USART2 initialization code is below.

void Usart2Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	USART_ClockInitTypeDef  USART_ClockInitStructure;

         USART_ClockStructInit(&USART_ClockInitStructure);
	USART_ClockInit(USART2, &USART_ClockInitStructure);
	//enable bus clocks
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 /*| RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO*/, ENABLE);
	//Set USART2 Tx (PA.02) as AF push-pull
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//Set USART2 Rx (PA.03) as input floating
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        //GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // Enable Tx and Rx
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	//Write USART2 parameters
	USART_Init(USART2, &USART_InitStructure);
	//Enable USART2
	USART_Cmd(USART2, ENABLE);
	//configure NVIC
	NVIC_InitTypeDef NVIC_InitStructure;
	//select NVIC channel to configure
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	//set priority to lowest
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
	//set subpriority to lowest
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
	//enable IRQ channel
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	//update NVIC registers
	NVIC_Init(&NVIC_InitStructure);
	//disable Transmit Data Register empty interrupt
	USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
	//enable Receive Data register not empty interrupt
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
Second image shows the data packet received. Packet has simple string with a framing char '*'.

Towards wireless iNEMO v2 ( STEVAL-MKI062V2 ) : Part 1

I started working on ARM 32-bit microcontroller board (iNEMO MEMES evaluation board) of ST Microelectronics. It has a COM connector( jumper J4) which is connected to the USART2 of STM32F103RE. But it is documented as UART2 in the User manual(UM0937) of the board. The jumper J4 doesn’t has any mark to show which is +3.3v or GND. So i had to check pins with multimeter. Figure shows where they are located in board.

I want to connect Sparkfun http://www.sparkfun.com/products/9358 module to J4 of iNEMO board. The electrical connections are shown in the figure (I  had experience in connecting Sparkfun Razor AHRS board to the Bluetooth mate).

Note: ST says J4 does not offer any transceiver; it is directly connected to the microcontroller pins. As thisprevents any overload/over-voltage on these pins. Moreover, J4 connector also provides a 3.3 V pin which can be used to supply a RS232 transceiver. Sinking too much current from this pin could damage the board.

Though i was afraid to connect the Bluetooth mate to iNEMO board, decided to connect because i was so curious. Fortunately there was no problem and the red LED on Bluetooth mate started blinking. I searched for Bluetooth devices and added ‘FireFly-xxxx’,  in my case it is connected to COM5. Then I opened Putty terminal program to communicate with the Bluetooth mate. First i typed command $$$ and pressed Enter, it shown CMD which means it is entered into command mode and started listening my commands from Putty terminal program.

USART2 is connected to bus APB1. This bus can work at 24/36MHz which is half of the bus APB2 frequency. Now i want to program iNEMO board to direct the sensors data to USART2, so that iNEMO become wireless.

Caution: I’m still afraid how much current Bluetooth module takes from Jumper J4.

OpenGL picking and Mouse click Input in Perspective Projection

After googling a day, I got some useful article here http://www.opengl.org/resources/faq/technical/selection.htm . But,we (me & my friend) already faced enough trouble.

So, I tried to write this for all our googling friends .

Shoot a pick ray through the mouse location and test for intersections with the currently displayed objects or mouse points. OpenGL doesn’t test for ray intersections , so you need to interact with OpenGL to generate the pick ray.

Step 1:   One way to generate a pick ray is to call gluUnProject() twice for the mouse location, first with winZ = 0.0 (at the
near plane),  then with winZ = 1.0 (at the far plane). Subtract the near plane call’s results from the far plane call’s results to
obtain the XYZ direction vector of your ray

                  NearToFarPlaneRay = FarPlaneResultNearPlaneResult .

Now the ray origin is the view location. When you are using gluUnProject  be careful with your winY here, because Microsoft Windows, X Windows(and others?) usually return mouse coordinates to your program with Y=0 at the top of the window, while OpenGL assumes Y=0 is at the bottom of the window. Assuming you’re using a default viewport, transform the Y value from window system coordinates to OpenGL coordinates as (windowHeight- mousePointY).

Windows to OpenGL ViewPort

Step 2: Now, we have to test for intersections. Use Line-Plane intersection here http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm
Take a pointOnPlane ( which may be center of your Viewing volume). Get the CameraPlaneNormal( [2],[6],[10] elements) from OpenGL ModelView matrix.
Get a rayfromNearPlane  pointOnPlane NearPlaneResult   . Compute dot products
d1CameraPlaneNormal . rayfromNearPlane    ,  d2 = CameraPlaneNormal . NearToFarPlaneRay
Compute ratio of dot products t = d1 ⁄ d2
Use the equation of line to get Point  PNearPlaneResult+ ( NearToFarPlaneRay× t )
Point P is what you need.

Follow

Get every new post delivered to your Inbox.