Restart: nRF24L01+ & STM32

It’s been a long time since I worked on this.

As recently I got two new USB2Serial converter plus an Android Uno acting like a USB2Serial Converter also (this can be done by connecting RST to GND [credits by someone else on the web, can’t find the source now]), besides I also have two C51 (STC12XXX) boards with working example for nRF24L01, I’m at a good position to start working on nRF24L01 with STM32 board now.

And today, since the example code of the C51 board for nRF24L01 is only for fixed-size payload communication, I’m able to do point to point communication with fixed-size payload using nRF24L01+ on STM32.

The next step would be change the code running on C51 and STM32 to use Dynamic Payload size.

[Previous problem causing nRF24L01+ not working with STM32 is that I made a typo mistake using a wrong register name macro in one of the helper functions]

[The code style is not so good: a lot of registers => a lot of register macro definition (register name, bits in the register, mask etc.). I’m wondering if there’s a better way to do this]


Bluetooth with UART Interface

I’m using the HMC10 bluetooth with UART interface along with my STM32F103 board. Now I’m trying to make it work with interrupt mode, however, as there’s another sensor MPU6050 taking up a lot of CPU time to read/write I2C interface to get YawPitchRoll data also using interrupt, the UART interrupt can not reach a high data rate. So I need to change it to DMA mode, which I have no idea to make it work right now. I will figure it out tomorrow.

MPU6050 (DMP) with STM32F103 mini board

Recently I’m trying to make the MPU6050 sensor work with the STM32F103 board. Since there’s work already done by someone else to make the MPU6050(DMP) available on boards with STM32F103. First, the document for DMP in MPU6050 is not available anywhere on the internet unless you register with a company/organization email address on the invsense “developer corner” through their website (even though, the document you get is not thorough enough to implement your own HAL driver for the DMP, let alone generating the firmware for the DMP. However according to some posts I found on the internet claiming that some opensource projects have signed certain agreement with invsense to gain support for use of DMP Anyway, the example project (including eMPL driver for MPU sensors) provided through the developer corner is enough to just extract YAW, PITCH & ROLL value from the sensor (I have no idea how the values are internally calculated using Gyro and Accel measures, and how they should be used in the flight control).

By far, the YAW, PITCH and ROLL values can be correctly extracted. I use python3 matplotlib for a simple host app to plot the three values.



I tried to rotate and tap the sensor board, the readings seemed okay for me. However, I’d like to try do a visualization as in the “FreeIMU Processing Example Project”(If I remember correctly), a 3D cube to show the orientation of the board).

TODO List:

1. 3D visualization. MPU6050 read out validation

2. PWMs on STM32F103

3. SPI on STM32F103 for wireless module

4. GPS

5. TFT2.8 Display

6. …

Chinese Characters Display Problem with Google-Chrome on Opensuse (KDE)

Just found out that the problem is related to font settings. One way to work around this is to modify the font configuration file under /etc/fonts/config.d/ change the sans-serif font (49-sansserif.conf) to some other font that supports Chinese language display (simsun).

OR use YAST to add Chinese Language support directly which will install the fonts and language packs for various applications for Help Documents etc.

BabyStep 4. STM32F103ZET6 I2C Interface

BabyStep 4. USART with DMA [Delayed]

BabyStep 4. I2C Interface [Check]

Today I tried the I2C interface with the STM32 board (with the Gyro GY-521 sensor).

Well, the I2C from the STM32F103ZE end is working now, but still not able to communicate with the GY-521 sensor (I need to read the sensor’s document AGAIN!!)

Unfortunately, just when I was trying to use I2C, I found that the material provided by the seller doesn’t contain example project for I2C. And the I2C1 port resides in PORTB (Pin6 & 7 as SCL and SDA), which conflicts with the port used by the TFT touch screen I bought. I checked the schematic of the board, found no I2C2 interface connected. For now, no screen is not a big problem, but I’m a little bit disappointed.

[—————————————Added 19/12/2013——————————————————]

After contacting the seller and referring to the datasheet of the chip, there IS an I2C2 interface available, which means that the schematic view is wrong. I2C2 goes with PB.10 & PB.11, also I’ve add another USART interface @PA.2&PA.3 to interface with the GPS sensor I have.


At first, there’s no output from the two I2C pins, after debugging I found that the I2C peripheral is always busy. Google Search results suggested that:

1. No pull up resistor connected causing the SCL/SDA pulled down by some other devices, seen as the I2C peripheral.

2. I2C peripheral is not correctly reset.   (

I tried to change the GPIO mode, but with no luck.

Finally, I switched the I2C configuration and enable order. IT WORKS.

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);      // Set clock for I2C1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   // Set clock for GPIOB
I2C_Cmd(I2C1, ENABLE); // Enable the I2C1
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);          // Assert Reset for the I2C1
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);        // Dessert Reset for the I2C1, not necessary as it seems now
I2C_Config(I2C1); // GY521 is connected to the I2C1 PB.6&7

void I2C_Config(I2C_TypeDef* I2Cx){
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PB.6 & 7
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    I2C_InitStructure.I2C_ClockSpeed = 400000; // 400kHz I2C fast mode
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // Tlow/Thigh = 2
    I2C_InitStructure.I2C_OwnAddress1 = 0x0000; // Use as I2C Master, Doesn't Matter
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // Enable ACK Message
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 0x4000

    I2C_Init(I2Cx, &I2C_InitStructure);
    return ;

Then, I found this tutorial with example code for basic I2C read/write

After some helper function to read/write register value from/to GY521, I had the I2C communication working @400KHz.


This is the Waveform for a cycle of Register Read from STM32 Device.

This is the waveform of a Burst Read cycle from Arduino device with example project from I2CDev library. (This is my target for STM32)

PS. There’s a CPAL I2C Library from STM32 focusing on providing User Application level I2C API, but for now, it’s too complex for me, I reserve it as future investigation.
BS 5. PWM / Timer ? [____]


BabyStep3: PRINTF with UART [Check]

The PRINTF with UART is working now with Interrupt Handler.
Even the Interrupt Handler in this case is not so complex, however, together with the procedure for registering Interrupt Handler requires some document reading.
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
/* Enable the USARTy Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
Another approach is to redirect the printf/scanf to use USART* by means of implementing fputc and fgetc as following:
int fputc(int ch, FILE *f){
	/* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART1, (uint8_t) ch);
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) ;
  return ch;

int fgetc(FILE *f){
	int c = 0;
	while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET) ;
	c = (int) USART_ReceiveData(USART1);
	fputc(c, f);
	return c;
1. Checking Status Flag (TC, RXNE) is still required
2. Neither TXE nor RXNE interrupt should be enabled in this way
3. scanf, printf functions are not as full-feature as standard C library function in other platforms
    e.g. with test code
int a = 0;
int b = 0;
int c = 0;
scanf("%d", &a);
scanf("%d", &b);
c = a + b;
printf("a+b = %d\r\n", c);
the output from picocom application looks like:

Step4. PWM Outputs, Timer etc [____]

Step4. USART with DMA [____]