Satellite speedometer on STM32F1 and FreeRTOS

The article will focus on a home-made speedometer that receives information about the current speed of the car, its coordinates and time from GPS satellites. The article also, I hope, will help by taking the first steps in the development of 32-bit microcontrollers with the Cortex M core and want to master one of the real-time operating systems (RTOS) for use in their developments.

Hardware implementation


I sat to myself, wrote in assembler under the 16th and 18th pic'ki, but I did not know grief. But the time has come to move on, study 32-bit microcontrollers. The choice fell on STM32 (namely, with the ARM Cortex M3 core) as the most promising - in RuNet exponentially growing volume of articles on them, microcontrollers are very attractive in price with a large amount of functional capabilities, have great prospects. With the growth of the project, you can transfer the work to much more productive versions of this kernel - from Cortex M to Cortex A. In addition, Apple uses the same core in its iPhone, iPad - ARM Cortex. Only more powerful, "A".

As a debug board, on which I implemented a satellite speedometer, I took one of the HY Redbull clones on my ebay for ~ $ 70:


The board, in addition to acquaintance with the STM32F103VCT6 microcontroller (72MHz, 512Kb FLASH, 64kb SRAM, 3ACP, 2CAP, DMA, FSMC, 5xUSART, 2xI2C, 3xSPI, CAN, USB 2.0 FS, etc.) and its built-in peripherals, allows you to master the basic external - MP3 / WMA decoder VS1003, Ethernet controller ENC28J60, 3.2-inch LCD screen with touchscreen (SSD1289 controller), SD cards (under the connector board), USB, CAN, RS232 / 485, CH376 controller (implements USB-Host interface / SD <-> UART / SPI / 8bit parallel for connecting an SD card and USB flash drives to the MK).

You can upload firmware to STM32 via UART, i.e. in fact, the programmer as such is not required. But it’s much more convenient to use debugging tools for which the JTAG port on the board is intended. You can spend another $ 20-50 on a JTAG debugger, but it’s much more advisable to take your own ST debugging board with the built-in Discovery series debugger. It costs from $ 10 (and at the same time it’s really everything, the basis of what is necessary for mastering STM32). I took the STM32F4-Discovery debugging board as a debugger for JTAG (generally speaking, I got it for free as a seminar visitor, and it costs about 600 rubles):



- it is intended for debugging ARM Cortex M4 (STM32F407), there is a built-in debugger on board (jumpers can switch from stm32f407 debugging to external board debugging via SWD, which I used by connecting my firebull board to the JTAG connector via SWD). This microcontroller can already work at a frequency of 168 MHz (though, the pebble of revision “A” has come across, damp, in this revision the performance drop is due to the memory accelerator). Flash 1MB, RAM 128KB. From the built-in peripherals, a USB device / host / OTG, 10/100 Ethernet, a camera interface (up to 1Mpix can be connected), hardware CRC counting, and a DSP processor deserve attention. From the external periphery, the board contains a LIS302DL MEMS accelerometer, an MP45DT02 digital MEMS microphone, and an ADC with I2S CS43L22 interface. Many examples go to the board, among which I especially liked the recorder player,
In terms of the choice of GPS-receiver was unoriginal. He took the very common EB-500. In order not to be tormented when wiring the board, I immediately took the EB-500 EVB Kit debug board with an active antenna in the kit:

The receiver itself outputs data via UART. But thanks to the UART-USB converter based on CP2102, the board can be connected via USB right away. The bundle comes with EB View software demonstrating the capabilities of the chip. You can see the output of NMEA data, set a list of fields that the chip needs to display, the frequency of their output, try out AGPS, and much more. You can use the Serial Port Monitor to watch the dialogue of EB View communication with the eb-500, and implement the corresponding eb-500 setup at the start of your device. Well, or study the datasheet) Also on the board there is already a 3-volt battery for storing the almanac when the device is turned off. For the subsequent quick start.
I also bought several cables for switching these boards - www.dealextreme.com/p/30cm-breadboard-wires-for-electronic-diy-40-cable-pack-80207#open%20full%20view- I recommend, the thing is extremely useful and convenient.


Software implementation

I chose the Keil environment. Convenient, widespread, equipped with an abundance of examples ... In a word - "mine." :) I used the library that came with the Firebull board to work with GLCD.

He chose FreeRTOS as the real-time operating system (RTOS) - there is a sea of ​​literature on it, it is actively developing, and due to these and other factors, it is more preferable compared to others - uC / OS, scmOS, etc. Plus it supports both preemptive and corporate, and combined modes of operation. And to me, as a beginner, this is a plus. :) If you are not familiar with RTOS at all, but want to get acquainted with an example of working with FreeRTOS and start using it in your projects, that is, a very good article that helped me:microsin.net/programming/ARM/freertos-part1.html - everything you need to start is described there. Then it remains to download the FreeRTOS distribution kit, take from there a ready-made example for your microcontroller, finalize it, and enjoy its work. Everything turns out to be not so complicated in practice, as it seems at first glance. :)

And now let’s take a look at the source code of the satellite speedometer, which receives data from the EB-500 GPS receiver and displays them on a 3.2 ”LCD screen: - create a semaphore (more about it below). we start 3 tasks with different priority. vLEDTask () we will have with the lowest priority - blink an LED ("I'm alive, not freezing!") and display the current system time on the screen. vGPSTask () with a higher priority, after starting it is corny ... falls asleep, waiting for the semaphore to be received.


int main(void)
{
    prvSetupHardware();
    vSemaphoreCreateBinary( xBinarySemaphore );
    if (xBinarySemaphore != NULL){
       xTaskCreate( vLEDTask, ( signed char * ) NULL , LED_TASK_STACK_SIZE , NULL , LED_TASK_PRIORITY , NULL );
       xTaskCreate( vGPSTask, ( signed char * ) NULL , GPS_TASK_STACK_SIZE,NULL , GPS_TASK_PRIORITY , NULL );
       // Запускаем планировщик задач
       vTaskStartScheduler();
    }
    return 0;
}




prvSetupHardware () does the following: First we set HCLK to clock the kernel, configure the NVIC interrupt controller (we need to enable the interrupt when receiving data on USART2), GPIO, USART2 pins (to which the GPS receiver is connected) at 9600 baud, 1 stop bit, without parity, 8bit, and the last line - RTC_Init () - turn on the built-in RTC peripherals - to display the current time and date. And if you stick the battery on the board, then there will be a real opportunity not to lose time when the power is turned off. :) Interrupt handlers are set in the stm32f10x_it.c file under the name in which they are indicated in the assembler startup _ *. S file. I needed only one handler - interruptions for receiving bytes from USART2 from a GPS receiver:

static void prvSetupHardware( void ){
    SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );// Тактируемся от HCLK
    NVIC_Configuration();//Настраиваем контроллер прерываний
    GPIO_Configuration();//Порты в/в, к которым подключены светодиоды
    USART2_9600(); //UART2 подключен к GPS EB-500, 9600бит/с
    RTC_Init();// настраиваем часы реального времени
    LCD_Initializtion();//Инициализация
    LCD_Clear(Blue);//Фоновый цвет экрана - синий
}






void USART2_IRQHandler(void)
{
    static portBASE_TYPE xHigherPriorityTaskWoken;
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){// Если прерывание – по приёму байта
       IrqBuf[IrqBuf_idx++]=USART_ReceiveData(USART2);// Получаем символ от EB-500
       if (IrqBuf_idx==BUFSIZE){// Буфер полон
          IrqBuf_idx=0;
       }
       else if (IrqBuf[IrqBuf_idx-1]==0x0A){// Конец строки
          IrqBuf[IrqBuf_idx]=0x00;
          IrqBuf_idx=0;
          xHigherPriorityTaskWoken = pdFALSE;
          xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
       }
       USART_ClearITPendingBit(USART2, USART_IT_RXNE);// Снимаем флаг прерывания
    }
}


- In the interrupt handler, we check for the end of the line. If you find the line feed character 0x0A, then you can parse a string with NMEA data from the EB-500. Directly in the interrupt handler, it is ideologically incorrect to carry out all the processing, and sometimes it is simply dangerous - you may not be in time until the next interrupt occurs. Processing was taken out in a separate task with the highest priority - vGPSTask (), but the task "sleeps", waiting for the semaphore to be received. And xSemaphoreGiveFromISR () in the interrupt handler is responsible for its output. We set the semaphore, reset the interrupt flag, and exit the handler - immediately control is transferred to vGPSTask (), even if another task was processed before the interrupt occurred, because this one gets the right to execute thanks to the semaphore.


Processing of NMEA data begins, namely, we are interested in the following lines from the EB-500: - each such message ends with a checksum (* 10, * 6E, * 18) and line feed characters (0x0D, 0x0A). All data is considered relevant only when $ GPRMC has “A” (as in the example above). Otherwise, we get "V". With “V” in our example, “no signal” is displayed. Next, we parse and display the data: * from the $ GPRMC package we pull out the current time in the format hhmmss.sss (in the example above it is 161229.487) * from the $ GPVTG package we get the current speed in kilometers per hour (0.2, K - 0, 2 kilometers per hour) * from the package $ GPGGA we get the geographic longitude and width in the format ddmm.mmmm / dddmm.mmmm (in the example, latitude is 3723.2475, longitude is 12158.3416)


$GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,,*10
$GPVTG,309.62,T,,M,0.13,N,0.2,K*6E
$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,,,,0000*18








The full source code of the project is in the archive at the end of the article. I note that the example is not without drawbacks, the main of which is that both tasks refer to the same hardware resource. You can solve it through mutexes or by writing a gatekeeper. I leave the decision interested in the quality of homework. But you can use an example without this - everything will work ...


Operating the system in my car gave positive results. Even if I start the car on a cold one, there are no problems with powering the board (hi ​​to the dc-dc down converter on the MC34063 base). The eb-500 had a cold start of 20 and a hot start of 0.5 minutes. As expected, when parked, a coordinate drift occurs - and, accordingly, speeds up to 0.5, and sometimes up to 7 km / h. For mobile devices, this can be neglected, but for a home-made satellite signaling based on the sim900 gsm module I'm working on, this is a tangible problem. Positive moment - only thanks to this speedometer did I find out that the standard speedometer of my car is in a hurry at 5km / h.


Now is the time for a photo shoot of a homemade satellite speedometer:





- 16:45:03 on the screen is UTC time. To transfer to Moscow, you need to add 4 hours (because the switch to winter time has been canceled). Those. I really took this picture yesterday at 19:45. Geographic coordinates - in hourly coordinates (hh.mm.ss.ms). i.e., in the first line of coordinates, it is 55 hours, 48 ​​minutes, 22 seconds and 830 milliseconds. To find this place, for example, through Yandex maps, we translate the coordinates into the required format: 55.48.22.830 = 55 + 48/60 + 22/3600 + 830/3600000 = ~ 55.806342 (round up to the sixth decimal place). For geographical width the same thing: 37.24.22.51 = 37 + 24/60 + 22/3600 + 510/3600000 = ~ 37,406253. We hammer the resulting value - 37.406253,55.806342 - into the Yandex.Mart search bar and get the result: maps.yandex.ru/?text=37.406253%2C55.806342&sll=&sspn=&z=&source=form


Using the uC / GUI graphics library, this example can be developed further. Display a graphic speedometer (and at the same time, connecting to the ignition coil through a resistive divider to the stm32 ADC, and the tachometer - you get a kind of digital car dashboard):



And you can make your own navigator (yes, not easy, but nothing is impossible):


In the GLCD library, the archive already has the file USER / GLCD / GLCD_UCGUI.c, which is the interface for connecting the uC / GUI to this and some other graphic screens. Download on the Internet itself uC / GUI I think is not difficult. So you have all the necessary tools to develop this example into something much more useful.


In the next article, we will discuss the further development of this work, for automating cars and houses - a system that combines the concepts of "Smart Home", "Smart Car", and includes the eCall / ERA-Glonass rescue system.

The project for Keil presented in the article can be downloaded here .

Also popular now: