Let's blink LED!
What is it? It's a bitmask for IOPCEN bit! So we don't need bitwise shifting one by pin number, we can use suitable bitmask! So, how will be looks first code line of us appilaction? Probably something like that :
But this is wrong. After compiling application, compiler return following error :
main.c(14): error: #20: identifier "RCC_APB2ENR" is undefined
Why? We use register name from Reference Manual, so why it is wrong? This is wrong, because all periperals are divided into structures that holds peripherals registers. This structures are defined in stm32f10x.h file. So go to this file and search for "Peripheral_registers_structures" string. You will see some of typedefs describing structures for all of periperals. Each structure holds all registers of peripheral. Naming scheme of periperal structures are following : PeriphName_TypeDef. So for RCC peripheral structure definition with registers are "RCC_TypeDef". So let's search for "RCC_TypeDef" string. We see, that registers name are slighty different from names from Reference Manual. Names in structure are without part of peripheral name. Register described in Reference Manual as RCC_APB2ENR in structure has name APB2ENR. OK, now we need name of structure variable. So let search again for RCC_TypeDef string. You should find following line :
Now all are clear! In stm32f10x.h file is defined macro RCC that in fact are pointer dereference to our RCC_TypeDef structure that resides at RCC_BASE address. If You search for RCC_BASE string, You find another macro, that defines RCC_BASE as base address of RCC peripheral in STM32F100 memory space. So now, we can use RCC macro as pointer to structure, that holds all register of RCC peripheral. Now we can write correct code for set IOPCEN bit in APB2ENR register of RCC peripheral :
Try to build application. Hooray! No errors! We have enabled clock for GPIOC peripheral and we can configure GPIO for driving LED.
Let me describe each element of this code line. GPIO->CRH mean of course access to GPIOC_CRH register. We want change configuration only for PC8, so remaining bits of this register should be unchanged. We realize that by reading contents of GPIO_CRH register and clear bits responsible for PC8 configuration. Macro CONFMASKH(8) give bitmask for clearing 4 lowest bits : 0xFFFFFFF0. Clearing this 4 bits will be done by bitwise AND of register with this bitmask. Next, we need to set configuration bits for PC8 suitable for driving LED. Output should be work as push-pull output. And what is this megahertzs? This specified slew rate on outputs pin. For driving LED we dont need fast edges of driving signals, so we use slowest slew ratio for PC8.
Controlling output state of GPIO pins can be realized on two ways : by writing port value to ODR (Output Data Register) register or by writing to BSRR (Bit Set/Reset Register) or BRR (Bit Reset Register). Writing to ODR register modyfies value of all pins of given GPIO port. Writing to BSRR/BRR registers modyfies state only this bits, that writing value has ones on bits position. For example to set bit PC8 we can use following code :
After execution of this line bit number 8 (and only this bit) of GPIOC will be set. Other bits remain unchanged. Upper 16 bits of BSRR register can be used to clearing pin state :
After execution of this line bit number 8 of GPIOC will be cleared. To resetting pin state we can use BRR register too :
After execution of this line, bit number 8 will be cleared. If we want clear single bit using ODR register, we must perform bitwise logical operations in Read-Modify-Write scheme :
but this operation is not atomic! After reading ODR state, his value can be changed (in interrupt for example), and after write modyfied value we can loose this change. So better use atomic operations with BSRR / BRR register.
(c) Radosław Kwiecień