Hi,
I'm using the STM32F103ZE uC on the MCBSTM32E development board. I tried the example programs, they all compile and download and run fine, but they are NOT SIMPLE. They use a lot of Library files etc, etc, etc. I just try to make some ports go high or low.
The example GPIO program states: - Enable the clock signal for the GPIO. - Configure the Alternate Function to use a GPIO (usually standard after reset). - Configure the GPIO pins as input or output. - Set remaining parameters like speed, pull-up/down. - Enable the GPIO. - Read from or write to the GPIO.
Can someone give me a simple (and I mean REALLY SIMPLE) program to control just one single GPIO port?
My questions to activate some port: - do I need something to know about internal clock signals? - do I need some startup file?
Thanks,
Henk
First off, put all of your library .C & .H files in the project directory and use #include "stm32f10x_ .h" instead of using the path #include <stm32f10x_ .h> method. (this way all of your source is in a single directory---and it is less confusing on how to set it up 'simply')
/*--------------------------------------------------------------------------. ; GPIO pins define ; '--------------------------------------------------------------------------*/ #define GPIO_Pin_0 ((u16)0x0001) /* Pin 0 selected */ #define GPIO_Pin_1 ((u16)0x0002) /* Pin 1 selected */ #define GPIO_Pin_2 ((u16)0x0004) /* Pin 2 selected */ #define GPIO_Pin_3 ((u16)0x0008) /* Pin 3 selected */ #define GPIO_Pin_4 ((u16)0x0010) /* Pin 4 selected */ #define GPIO_Pin_5 ((u16)0x0020) /* Pin 5 selected */ #define GPIO_Pin_6 ((u16)0x0040) /* Pin 6 selected */ #define GPIO_Pin_7 ((u16)0x0080) /* Pin 7 selected */ #define GPIO_Pin_8 ((u16)0x0100) /* Pin 8 selected */ #define GPIO_Pin_9 ((u16)0x0200) /* Pin 9 selected */ #define GPIO_Pin_10 ((u16)0x0400) /* Pin 10 selected */ #define GPIO_Pin_11 ((u16)0x0800) /* Pin 11 selected */ #define GPIO_Pin_12 ((u16)0x1000) /* Pin 12 selected */ #define GPIO_Pin_13 ((u16)0x2000) /* Pin 13 selected */ #define GPIO_Pin_14 ((u16)0x4000) /* Pin 14 selected */ #define GPIO_Pin_15 ((u16)0x8000) /* Pin 15 selected */ #define GPIO_Pin_All ((u16)0xFFFF) /* All pins selected */ void Simple_Example( void ) { GPIO_InitTypeDef gpio_initstructure; // typedef found in "stm32f10x_gpio.h" // [Library] /*------------------------------------------------------------------. ; GPIO C ; ;-------------------------------------------------------------------; ; GPIOC 'GPIO_InitStructure' Configuration ; ;-------------------------------------------------------------------; ; Enable ONLY pins 6, 7, 8, 9 for Alternate Function Push/Pull mode ; '------------------------------------------------------------------*/ gpio_initstructure.GPIO_Pin = 0x0000 // used for a holder for -OR- //| GPIO_Pin_0 // ADC-10 = //| GPIO_Pin_1 // ADC-11 = //| GPIO_Pin_2 // ADC-12 = //| GPIO_Pin_3 // ADC-13 = //| GPIO_Pin_4 // ADC-14 = //| GPIO_Pin_5 // ADC-15 = | GPIO_Pin_6 // PWM-T3.1 = | GPIO_Pin_7 // PWM-T3.2 = | GPIO_Pin_8 // PWM-T3.3 = | GPIO_Pin_9 // PWM-T3.4 = //| GPIO_Pin_10 // UART4 TxD (Diagnostics) //| GPIO_Pin_11 // UART4 RxD (Diagnostics) //| GPIO_Pin_12 // "USART3_CK" [ ?? SPARE ?? ] //| GPIO_Pin_13 // Tamper/RTC = "TP32" //| GPIO_Pin_14 // OSC32(IN) //| GPIO_Pin_15; // OSC32(OUT) ; // Semi-colon placed here for convenience /*------------------------------------------------------------------. ; GPIO C Peripheral speed (as fast as possible-- there is no need ; ; to save energy since this project is not battery operated (yet) ; '------------------------------------------------------------------*/ gpio_initstructure.GPIO_Speed= GPIO_Speed_50MHz; /*------------------------------------------------------------------. ; The I/O port pins are configured for Push-Pull operations ; '------------------------------------------------------------------*/ gpio_initstructure.GPIO_Mode = GPIO_Mode_AF_PP; /*------------------------------------------------------------------. ; GPIO C Initialization using the data in 'GPIO_InitStructure' ; '------------------------------------------------------------------*/ GPIO_Init( GPIOC, &gpio_initstructure ); // PORT C update [Library] }
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
This doesn't follow the above code fragment, but if you configure the ports for non-Alternate function, but Push/Pull you can use these #defines to set and clear port-pins...
/*--------------------------------------------------------------------------. ; ; ; Addresses and offsets to the General Purpose Input & Output Pins ; ; ; '--------------------------------------------------------------------------*/ #define GPIOx_OFFSET_CRL (0x00)// Port configuration register low (GPIOx_CRL) #define GPIOx_OFFSET_CRH (0x04)// Port configuration register high (GPIOx_CRH) #define GPIOx_OFFSET_IDR (0x08)// Port input data register (GPIOx_IDR) #define GPIOx_OFFSET_ODR (0x0C)// Port output data register (GPIOx_ODR) #define GPIOx_OFFSET_BSRR (0x10)// Port bit set/reset register (GPIOx_BSRR) #define GPIOx_OFFSET_BRR (0x14)// Port bit reset register (GPIOx_BRR) #define GPIOx_OFFSET_LCKR (0x18)// Port configuration lock register (GPIOx_LCKR) #define GPIO_MAP_PA ( (vu32) 0x40010800 ) #define GPIO_MAP_PB ( (vu32) 0x40010C00 ) #define GPIO_MAP_PC ( (vu32) 0x40011000 ) #define GPIO_MAP_PD ( (vu32) 0x40011400 ) #define GPIO_MAP_PE ( (vu32) 0x40011800 ) #define GPIO_MAP_PF ( (vu32) 0x40011C00 ) #define GPIO_MAP_PG ( (vu32) 0x40012000 ) #define PA_BSRR ( GPIO_MAP_PA + GPIOx_OFFSET_BSRR ) // setting individual bits #define PB_BSRR ( GPIO_MAP_PB + GPIOx_OFFSET_BSRR ) #define PC_BSRR ( GPIO_MAP_PC + GPIOx_OFFSET_BSRR ) #define PD_BSRR ( GPIO_MAP_PD + GPIOx_OFFSET_BSRR ) #define PE_BSRR ( GPIO_MAP_PE + GPIOx_OFFSET_BSRR ) #define PF_BSRR ( GPIO_MAP_PF + GPIOx_OFFSET_BSRR ) #define PG_BSRR ( GPIO_MAP_PG + GPIOx_OFFSET_BSRR ) #define PA_BRR ( GPIO_MAP_PA + GPIOx_OFFSET_BRR ) // resetting individual bits #define PB_BRR ( GPIO_MAP_PB + GPIOx_OFFSET_BRR ) #define PC_BRR ( GPIO_MAP_PC + GPIOx_OFFSET_BRR ) #define PD_BRR ( GPIO_MAP_PD + GPIOx_OFFSET_BRR ) #define PE_BRR ( GPIO_MAP_PE + GPIOx_OFFSET_BRR ) #define PF_BRR ( GPIO_MAP_PF + GPIOx_OFFSET_BRR ) #define PG_BRR ( GPIO_MAP_PG + GPIOx_OFFSET_BRR ) #define PC0 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_0 ) ) // bit 0000.0000:0000.0001 #define PC1 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_1 ) ) // 0000.0000:0000.0010 #define PC2 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_2 ) ) // 0000.0000:0000.0100 #define PC3 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_3 ) ) // 0000.0000:0000.1000 #define PC4 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_4 ) ) // 0000.0000:0001.0000 #define PC5 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_5 ) ) // 0000.0000:0010.0000 #define PC6 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_6 ) ) // 0000.0000:0100.0000 #define PC7 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_7 ) ) // 0000.0000:1000.0000 #define PC8 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_8 ) ) // 0000.0001:0000.0000 #define PC9 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_9 ) ) // 0000.0010:0000.0000 #define PC10 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_10) ) // 0000.0100:0000.0000 #define PC11 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_11) ) // 0000.1000:0000.0000 #define PC12 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_12) ) // 0001.0000:0000.0000 #define PC13 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_13) ) // 0010.0000:0000.0000 #define PC14 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_14) ) // 0100.0000:0000.0000 #define PC15 ( (u16)*(((vu32 *)PC_IDR) ) & (GPIO_Pin_15) ) // 1000.0000:0000.0000 #define PC0_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_0 ) #define PC1_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_1 ) #define PC2_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_2 ) #define PC3_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_3 ) #define PC4_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_4 ) #define PC5_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_5 ) #define PC6_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_6 ) #define PC7_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_7 ) #define PC8_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_8 ) #define PC9_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_9 ) #define PC10_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_10 ) #define PC11_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_11 ) #define PC12_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_12 ) #define PC13_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_13 ) #define PC14_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_14 ) #define PC15_RESET ( (*(vu32 *)PC_BRR) = GPIO_Pin_15 ) #define PC0_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_0 ) #define PC1_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_1 ) #define PC2_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_2 ) #define PC3_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_3 ) #define PC4_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_4 ) #define PC5_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_5 ) #define PC6_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_6 ) #define PC7_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_7 ) #define PC8_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_8 ) #define PC9_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_9 ) #define PC10_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_10 ) #define PC11_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_11 ) #define PC12_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_12 ) #define PC13_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_13 ) #define PC14_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_14 ) #define PC15_SET ( (*(vu32 *)PC_BSRR) = GPIO_Pin_15 ) void Simple_Toggle( void ) { PC6_SET; // force to 1 PC6_RESET; // force to 0 }
Don't forget to get a copy of UM0427.PDF User Manual "ARM®-based 32-bit MCU STM32F101xx and STM32F103xx firmware library" from STMicro for the Library function definitions.
Oh, yeah... you'll need this too..
#define PA_IDR ( GPIO_MAP_PA + GPIOx_OFFSET_IDR ) // #define PB_IDR ( GPIO_MAP_PB + GPIOx_OFFSET_IDR ) // #define PC_IDR ( GPIO_MAP_PC + GPIOx_OFFSET_IDR ) // #define PD_IDR ( GPIO_MAP_PD + GPIOx_OFFSET_IDR ) // #define PE_IDR ( GPIO_MAP_PE + GPIOx_OFFSET_IDR ) // #define PF_IDR ( GPIO_MAP_PF + GPIOx_OFFSET_IDR ) // #define PG_IDR ( GPIO_MAP_PG + GPIOx_OFFSET_IDR ) //
Thanks for all the info, I studied for 4 hours on all header files and now it's clear to me and I made a REALLY SIMPLE program and: IT WORKS!!!!!!
The real problem was the GPIO clock that should be switched on. I think I'm an expert now. ;-)
//------------------------------------------------------------ // // Very simpe program to control the 8 PB08-PB15 Leds on the // Keil MCBSTM32E board using a STM32F103ZE micro controller. // // This program will show a toggling 0xAAAA / 0x5555 pattern // on the onboard Leds appr. each 300ms. // // Copyright! Non of this shall be reproduced in any way! ( ;-) ) // // 2010.08.06 // Henk van Winkoop // The Netherlands // // Note: only lowercase names are used to avoid YELLING. // //------------------------------------------------------------ //============================================================ // MAIN //============================================================ int main(void){ //------------------------------ // declare variables //------------------------------ //CRN register for input output settings int *crh; //ODR register for output data int *odr; //APB2ENR register for clock selection int *apb2enr; //delay counter variable int i; //------------------------------ // assign addresses to pointers //------------------------------ //define the address of crh register crh=(int*)(0x40010C04); //define the address of odr register odr=(int*)(0x40010C0C); //define the the address of the apb2enr register apb2enr=(int*)0x40021018; //------------------------------ // init the micro controller //------------------------------ //enable the GPIO clock for port GPIOB *apb2enr|=0x0008; //set all PB08-PB15 ports as output *crh=0x33333333; //------------------------------ // main loop //------------------------------ //forever do... for(;;){ //roughly wait 300ms for(i=0;i<0x40000;i++){ }//for //switch only all even-numbered Leds on *odr=0x0000aaaa; //roughly wait 300ms for(i=0;i<0x40000;i++){ }//for //switch only all odd-numbered Leds on *odr=0x00005555; }//for }//main
Thanks for listening folks!
Me again,
I forgot to tell:
the only additional file needed is: STM32F10x.s
Well, now that I'm on 'steam':
I've modified my program so that is runs using the official added STMicroelectronics header files. Then this program gets even smaller.
I hope other newbies will appreciate this.
All you need (except love) is: - the GPIO header file - the startup file - init the GPIO clock - set the GPIO port to Output - write data to the port
So this is the real answer I was looking for. . .
//------------------------------------------------------------ // // Very simpe program to control the 8 PB08-PB15 Leds on the // Keil MCBSTM32E board using a STM32F103ZE micro controller. // // This program will show a toggling 0xAAAA / 0x5555 pattern // on the onboard Leds appr. each 300ms. // // Copyright! Non of this shall be reproduced in any way! ( ;-) ) // // 2010.08.06 // Henk van Winkoop // The Netherlands // // The only additional files needed is: STM32F10x.s // // This version uses the STMicroelectronics manufacturer // setup header files. // //------------------------------------------------------------ //include the file that defines all kind of GPIO stuff #include <stm32f10x_gpio.h> //============================================================ // MAIN //============================================================ int main(void){ //------------------------------ // declare variables //------------------------------ //delay counter variable int i; //------------------------------ // init the micro controller //------------------------------ //enable the GPIO clock for port GPIOB RCC->APB2ENR|=0x0008; //set all PB08-PB15 ports as output GPIOB->CRH=0x33333333; //------------------------------ // main loop //------------------------------ //forever do... for(;;){ //roughly wait 300ms for(i=0;i<0x40000;i++){ }//for //switch only all even-numbered Leds on GPIOB->ODR=0x0000aaaa; //roughly wait 300ms for(i=0;i<0x40000;i++){ }//for //switch only all odd-numbered Leds on GPIOB->ODR=0x00005555; }//for }//main
Thanks for listening...
How long will your delay take if you try to change the optimization level?
Might there be a problem?
Is there any good way to overcome this problem?
as far as I know you should add some assembler nop() instruction inside a 'for' loop to be sure this code is not optimized into the recycle bin. This is the way to do it with 8051 or Atmel AVR uC's so I assume Cortex will have some identical code.
www.8052.com/.../162556
A nop() only adds a delay if the compiler knows that the instruction time of the nop() is an important side effect. If the compiler doesn't, then the nop is "nothing" and can be removed.
Besides - even if you do have a nop instruction in the loop, the optimization level will change the number of machine cycles neede for the loop primitives which means that the total time will change depending on what code that is generated for the loop.
A nop() can be good when you need sub-microsecond delays. Maybe get 20ns extra delay between activating two GPIO signals (under the assumption that the compiler knows and honors the "side effect" of the nop).
Whenever you want longer delays, you should look into the timer system. Either busy-looping while waiting for a timer register to reach a certain value, or do something else while waiting for the timer to generate an interrupt.
The only time you may consider software delay loops, is if you write the delay loop in assembler. And then you better avoid trying to inline that assembler inside a C function - write the delay() function fully in assembler.
The PDF does not exist any more!
:-(
See: my.st.com/.../Flat.aspx
no UM0427.PDF ?? Oh no! >:| --Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
Well, then gleen the data from:
www.st.com/.../familiesdocs-110.html
P.S. Is there an easy site to post the .PDF file that I have? Just curious.
It's all in the helpfile (.chm) included in the download - the point was that it's no longer available as a .pdf