In this blog I write all the activities I do, which are mainly in the embedded electronics and robotics field. I also share here my political opinions and my experiences in life
The STM32F4 discovery is a wonderful board but it is really not freindly when testing with all its ugly male connectors that it is impossible to put it in a lab board.
I don't know if anyone did this before, but I made a small adapter in eagle for this board so it can be easily integrated with other test or prototyping project or it can be simply used in a hole PCB board.
Hi,
Stepper motors are very commun in many applications, they are widely used in printers scanners and many other equipements thanks to their easy control.
I really advice you to understand how bipolar stepper works before testing the following code.
Start from here !
The following code is for controlling a bipolar stepper motor using STM32F4 discovery board.
I used a l293D for power interface between the stepper and the board like the following image:
And The I used this simple code to control my stepper in one direction with fixed speed using half step control.
Hello,
This time I'll give you a short tutorial about how to use timers with the STM32.
Timers are very useful when it comes to make a precise period of time independantly from your main loop execution.
The stm32F4 has many timers each one with a specific need. I'm just going to use the Timer 2 to make an interruption each 0.25 sec.
I use a C# program to calculate what values to put in the prescaler and the periode to get my required interruption time. https://www.mediafire.com/?bq21q5qd7frcvba
The code has comments in it but if there is something that is not clear explained in the comments below, I'll be happy to answer.
void TIM2_IRQHandler(void){
static short i = 0;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_WriteBit(GPIOD,GPIO_Pin_13,i++);
GPIO_ToggleBits(GPIOD, GPIO_Pin_14);
}
}
void INTTIM_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 1000000 - 1; // 1 MHz down to 1 KHz (1 ms)
TIM_TimeBaseStructure.TIM_Prescaler = 43- 1; // 24 MHz Clock down to 1 MHz (adjust per your clock)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM IT enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
int main(void)
{
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
STM_EVAL_LEDInit(LED5);
STM_EVAL_LEDInit(LED6);
INTTIM_Config();
while(1);
}
LCD can be a very useful part in any microcontroller based project. It helps to monitor variables and program status with simple texts or numbers.
For this application I used a JHD 162 A alphanumeric LCD, like the picture above.
It hast 16 pins specified like this
VEE is used for contrast, so attache it to a potentiometer and choose your best contrast. Or simply plug it to 5V if you need maximum contrast.
D0, D1, D2, D3 are grounded
I managed to find a library for STM32VL, so I needed to bring some changes to it before it works. This library works both for JHD 162A and the hd44780.
lcd_hd44780.h
//******************************************************************************
// THE SOFTWARE INCLUDED IN THIS FILE IS FOR GUIDANCE ONLY.
// AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT
// OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
// FROM USE OF THIS SOFTWARE.
//******************************************************************************
//##############################################################################
// lcd_hd44780.h
//##############################################################################
//****************************************************************************//
#include "main.h"
#define LCD_GPIO GPIOD
#define LCD_CLK_LINE RCC_AHB1Periph_GPIOD
#define LCD_D4 GPIO_Pin_1
#define LCD_D5 GPIO_Pin_3
#define LCD_D6 GPIO_Pin_5
#define LCD_D7 GPIO_Pin_7
#define LCD_RS GPIO_Pin_0
#define LCD_RW GPIO_Pin_2
#define LCD_EN GPIO_Pin_4
//******************************************************************************//
#define HD44780_CLEAR 0x01
#define HD44780_HOME 0x02
#define HD44780_ENTRY_MODE 0x04
#define HD44780_EM_SHIFT_CURSOR 0
#define HD44780_EM_SHIFT_DISPLAY 1
#define HD44780_EM_DECREMENT 0
#define HD44780_EM_INCREMENT 2
#define HD44780_DISPLAY_ONOFF 0x08
#define HD44780_DISPLAY_OFF 0
#define HD44780_DISPLAY_ON 4
#define HD44780_CURSOR_OFF 0
#define HD44780_CURSOR_ON 2
#define HD44780_CURSOR_NOBLINK 0
#define HD44780_CURSOR_BLINK 1
#define HD44780_DISPLAY_CURSOR_SHIFT 0x10
#define HD44780_SHIFT_CURSOR 0
#define HD44780_SHIFT_DISPLAY 8
#define HD44780_SHIFT_LEFT 0
#define HD44780_SHIFT_RIGHT 4
#define HD44780_FUNCTION_SET 0x20
#define HD44780_FONT5x7 0
#define HD44780_FONT5x10 4
#define HD44780_ONE_LINE 0
#define HD44780_TWO_LINE 8
#define HD44780_4_BIT 0
#define HD44780_8_BIT 16
#define HD44780_CGRAM_SET 0x40
#define HD44780_DDRAM_SET 0x80
//##############################################################
void lcd_init(void);
void lcd_cls(void);
void lcd_str(unsigned char * text);
void lcd_strxy(unsigned char * text, unsigned char x, unsigned char y);
void lcd_locate(unsigned char x, unsigned char y);
void lcd_int(int n);
void lcd_intxy(int n, unsigned char x, unsigned char y);
//###############################################################
void lcd_writedata(unsigned char dataToWrite);
void lcd_writecommand(unsigned char commandToWrite);
void lcd_writebinary(unsigned int var, unsigned char bitCount);
void lcd_addchar (unsigned char chrNum, unsigned char n, const unsigned char *p);
I've made some experiments using the STM32F3 discovery board, which is amazing by the way, and the mems(Micro ElectroMechnical Systems) in the board.
For more information about the board check this link where you will find all the technical hardware and software examples made with many IDEs.
The main idea of this article is to make a standalone IMU (Inertial Measurement Unit) using only the STM32F3 board, because it has all the necessary hardware for making a complete 9 DOF IMU.
To do so I need to read both of the Gyroscope and the accelerometer data collected in a way so I can send later to the PC using VCP (USB CDC).
I started with the VCP example for the STM32303c eval board, you can find here
And then I add both of stm32f3_discovery_lsm303dlhc.c and stm32f3_discovery_l3gd20.c, this two file could be found in the utitli folder of the firmware support for the STM32F3 board can be found here.
Then later I found this great files to give more abstract function to deal with the mems.
/**
******************************************************************************
* @file main.c
* @author MCD Application Team
* @version V4.0.0
* @date 21-January-2013
* @brief Virtual Com Port Demo main file
******************************************************************************
* @attention
*
**
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "hw_config.h"
#include "usb_lib.h"
#include "usb_desc.h"
#include "usb_pwr.h"
#include "Accelerometer.h"
#include "Gyro.h"
#include
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
float AccData[3];
float GyroData[3];
char data[9];
int i =0;
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : main.
* Description : Main routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int main(void)
{
// data[0] = 'K';
Set_System();
Set_USBClock();
USB_Interrupts_Config();
USB_Init();
Acc_Config();
GyroConfig();
while (1)
{
Acc_ReadData(AccData);
GyroReadAngRate(GyroData);
sprintf(data,"%F",AccData[0]);
sprintf(data+3,"%F",AccData[1]);
sprintf(data+6,"%F",AccData[2]);
UserToPMABufferCopy((uint8_t*)data,ENDP1_TXADDR,9);
SetEPTxCount(ENDP1, 9);
SetEPTxValid(ENDP1);
sprintf(data,"%F",GyroData[0]);
sprintf(data+3,"%F",GyroData[1]);
sprintf(data+6,"%F",GyroData[2]);
UserToPMABufferCopy((uint8_t*)data,ENDP1_TXADDR,9);
SetEPTxCount(ENDP1, 9);
SetEPTxValid(ENDP1);
// printf("%s\n",AccData);
}
}
#ifdef USE_FULL_ASSERT
/*******************************************************************************
* Function Name : assert_failed
* Description : Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* Input : - file: pointer to the source file name
* - line: assert_param error line source number
* Output : None
* Return : None
*******************************************************************************/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{}
}
#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
DMA stands for direct memory access, this can be used one data needed to be transferred from place to another as it is for example from RAM to FLASH memory, from I2C, SPI or ADC to memory.
The DMA controller replaces the CPU in data transfer operation so the CPU can be freed to do other tasks.
DMA can be useful when there is critical data to receive and the user wants to see all data, even using the interrupt I/O there still time wasted while context switching, this can be elure with DMA.
The STM32 microcontroller has 2 DMA Controllers (DMA1, DMA2) and there are connected to the peripheral and memory through channels.
In the following example, I will illustrate the use of DMA with ADC.
In many embedded projects, we have to deal with signals directly from nature, like temperature, pressure, current, etc... Theses signals are analog by default and in most of cases we use sensors that converts these analog signals to analog electrical voltage to be injected in the microcontroller to do some work.
Unfortunately, microcontrollers are digital and just can't deal with analog signals so these signals must be converted again to digital signals that is comprehensible by the microcontroller.
For this purpose, microcontroller's manufacturers usually incorporate an ADC into the microcontroller. ADC is actually stands for Analog to Digital Converter. This module is omnipresent in most of microcontrollers.
I'm going to use the STM32F4 discovery board to interface an analog input provided by a potentiometer and visualize the received data with the watch feature while debugging the program.
#include "stm32f4xx_adc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
int ConvertedValue = 0; //Converted value readed from ADC
void adc_configure(){
ADC_InitTypeDef ADC_init_structure; //Structure for adc confguration
GPIO_InitTypeDef GPIO_initStructre; //Structure for analog input pin
//Clock configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//The ADC1 is connected the APB2 peripheral bus thus we will use its clock source
RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN,ENABLE);//Clock for the ADC port!! Do not forget about this one ;)
//Analog pin configuration
GPIO_initStructre.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0
GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode
GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down
GPIO_Init(GPIOC,&GPIO_initStructre);//Affecting the port with the initialization structure configuration
//ADC structure configuration
ADC_DeInit();
ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Right;//data converted will be shifted to right
ADC_init_structure.ADC_Resolution = ADC_Resolution_12b;//Input voltage is converted into a 12bit number giving a maximum value of 4096
ADC_init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once
ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1 (actually I'm not sure about this one :/)
ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion
ADC_init_structure.ADC_NbrOfConversion = 1;//I think this one is clear :p
ADC_init_structure.ADC_ScanConvMode = DISABLE;//The scan is configured in one channel
ADC_Init(ADC1,&ADC_init_structure);//Initialize ADC with the previous configuration
//Enable ADC conversion
ADC_Cmd(ADC1,ENABLE);
//Select the channel to be read from
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_144Cycles);
}
int adc_convert(){
ADC_SoftwareStartConv(ADC1);//Start the conversion
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion
return ADC_GetConversionValue(ADC1); //Return the converted data
}
int main(void){
adc_configure();//Start configuration
while(1){//loop while the board is working
ConvertedValue = adc_convert();//Read the ADC converted value
}
}
In this tutorial I'm going to show you one of the most used IP in any ST microcontroller the GPIO. What you need to know witch could be obvious to some that we are actually going to program the microcontroller in the board and not the board!!
The microcontroller of the STM32F4DISCOVERY board is STM32F407VGT ==> Datasheet
I'm using coocox for developing and it's an eclipse based IDE very friendly and intuitive.
The GPIO IP:
As I said it stands for Gneral purpose Input Output,
Each of the GPIO pins can be configured by software as output (push-pull or open-drain,
with or without pull-up or pull-down), as input (floating, with or without pull-up or pull-down)
or as peripheral alternate function. Most of the GPIO pins are shared with digital or analog
alternate functions. All GPIOs are high-current-capable and have speed selection to better
manage internal noise, power consumption and electromagnetic emission.
The I/O configuration can be locked if needed by following a specific sequence in order to
avoid spurious writing to the I/Os registers.
Fast I/O handling allowing maximum I/O toggling up to 84 MHz.
(From datasheet)
There are 5 GPIOs in the STM32 microcontroller (GPIOA,GPIOB,GPIOC,GPIOD,GPIOE) every GPIO has 16 configurable pin and each has 7 registers:
Two are used to configure the sixteen port bits individually, (CRL,CRH)
two are used to read/write the sixteen port bits in parallel, (ODR,IDR)
two are used to set/reset the sixteen port bits individually, (BSRR,BRR)
and one is used to implement a “locking sequence” that is intended to prevent rogue code from accidentally modifying the port configuration (LCKR)
First start new project choose chip (ST-STM32F407VG) . Later on the repositry window will appear, we will do some blinking so we definitely need the GPIO, click on the GPIO check box, RCC, CMSIS boot and M4 CMSIS Core are automatically checked.
In the project tree double click on main.c
GPIO as output :
What are we going to do is to make the leds embedded on the board to blink together every 1sec but to do so we need to know to witch pin and witch GPIO these leds are connected in our STM32F4DISCOVERY board.
According to the board schematics in pag 6
The leds are connected to (PD12/PD13/PD14/PD15) the GPIO used is then GPIOD and the pins are (12, 13, 14, 15)
So what we need to do is explained in the following flowchart:
GPIO as INPUT :
Say that we need to read input from the outside world like buttons or switches we have to use the GPIO too.
In this case we are going to read the embedded button in the STM32F4DISCOVERY board.
According to the board schematics this button is connected to the PA0 (GPIOA, pin 0).
What are we going to do is to set the leds on when the button is set and resetting them when the button is not set.
But we need to configure the GPIOA and the pin 0 as input before we can read data from it.
I got my STM32F4DISCOVERY board a few days ago and I'm so excited to try it.
This board is definitely one and unique board made by st for amateurs and professional to discover easily and with pleasure the strength of the STM32F4 series.
The board is really rich with features (copy past from the STM32F4DISCOVERY datasheet)
STM32F407VGT6 microcontroller featuring 32-bit ARM Cortex-M4F core, 1 MB Flash, 192 KB RAM in an LQFP100 package
On-board ST-LINK/V2 with selection mode switch to use the kit as a standalone ST-LINK/V2 (with SWD connector for programming and debugging)
Board power supply: through USB bus or from an external 5 V supply voltage
External application power supply: 3 V and 5 V
LIS302DL, ST MEMS motion sensor, 3-axis digital output accelerometer (Amazing !!!)
MP45DT02, ST MEMS audio sensor, omni-directional digital microphone
CS43L22, audio DAC with integrated class D speaker driver
Eight LEDs:LD1 (red/green) for USB communicationLD2 (red) for 3.3 V power onFour user LEDs, LD3 (orange), LD4 (green), LD5 (red) and LD6 (blue)2 USB OTG LEDs LD7 (green) VBus and LD8 (red) over-current
Two push buttons (user and reset)
USB OTG FS with micro-AB connector (amazing for a microcontroller)
Extension header for all LQFP100 I/Os for quick connection to prototyping board and easy probing
This board can be used in many application with its DSP it can solve complex Digital signal functions used in filter computing plus it has the FPU (Floating point unit) that allows the STM32F4 to deal with floats up to 10exp-18 precision and that would be very useful in application that needs media processing or precision calculations.
I will post some tutorials talking about my experience with board.
Have you ever wanted to do the same thing at the same time to win more time?! Cleaning the house while doing your homework :D that would be very helpful.
Working with embedded systems made crucial to deal with different tasks at the same time while having (most of the time) only one CPU that can handle only one task at a time.
To schedule between different tasks, embedded systems use RTOS (real time operating systems) which is in same how a little software is responsible to manage all the different tasks that want to use the CPU.
I found lately a wonderful tool to programme STM32 microcontrollers which is CoIDE from Coocox. It's based on the eclipse which makes programming the STM32 a lovely journey you don't want to miss.
You can download Cocenter from here which contains all the other great software that come with CoIDE like CoOS which is a free RTOS that we will use it in this Tutorial.
So... Our mission is to blink a led in an infinite task and to watch for the value of the button in an other task.
I used the STM32 discovery board that contains an STM32F100RB.
After creating a project in your CoIDE, make sure to add the GPIO, RCC and CoOS libraries from the repository.