I want to create my own driver on stm32f1 board. I want to control MCU build_in led but I can't solve. I am trying to make PortC pin 13 pin as output (push-pull) mode, after that I want to set bit. but code isn't work
#include<stdint.h>
#define RCC_BASE_ADDR 0x40021000UL //RCC BASE ADDRESS
#define RCC_APB2_ENR_OFFSET 0x18UL
#define RCC_APB2_ENR_ADDR (RCC_BASE_ADDR + RCC_APB2_ENR_OFFSET)
//#####################################
#define GPIOC_BASE_ADDR 0x40011000UL
#define GPIO_CTR_OFFSET 0x00UL //GPIO controll register
#define GPIO_CTR_ADDR (GPIOC_BASE_ADDR + GPIO_CTR_OFFSET)
#define GPIO_MODE_OUT_OFFSET 0x0CUL //GPIO OUTPUT MODE
#define GPIO_MODE_OUT_ADDR (GPIOC_BASE_ADDR + GPIO_MODE_OUT_OFFSET)
#define GPIO_BSRR_OFFSET 0x10UL //GPIO BIT SET RESET REGISTER
#define GPIO_BSRR_ADDR (GPIOC_BASE_ADDR + GPIO_BSRR_OFFSET)
int main()
{
uint32_t *pRCCAPB2EnReg = (uint32_t *)RCC_APB2_ENR_ADDR;
uint32_t *pGPIOCtr = (uint32_t *)GPIO_CTR_ADDR;
uint32_t *pGPIOModeOut = (uint32_t *)GPIO_MODE_OUT_ADDR;
uint32_t *pGPIOBSRR = (uint32_t *)GPIO_BSRR_ADDR;
*pRCCAPB2EnReg |= (1<<4);
*pGPIOCtr |= (0<<3);
*pGPIOCtr |= (0<<2);
*pGPIOCtr |= (0<<1);
*pGPIOCtr |= (1<<0);
*pGPIOModeOut |= (1<<13);
*pGPIOBSRR |= (1<<13);
return 0;
}
First, add a couple waste cycles after you enable GPIO port clock for changes to take effect. It can be anything really, as long as it's a couple of cycles (not nops tho, CPU is free to ignore nops as per ARM). Reading the bit you just set will be enough.
But it's not the main problem here. Let's open the reference manual RM0008 at page 172, GPIO registers.
You use the wrong GPIO control register to configure the GPIO. You use CRL with the offset of 0x00 (from GPIO Base), but it's only for the pins 0-7. Pins 8-15 are configured in the register CRH with the offset of 0x04.
We need to configure GPIOC pin 13. It will be in the register CRH, fields CNF13 (2 bits wide, starting at position 22) and MODE13 (2 bits wide, starting at position 20), which sit next to each other. The reset state of these fields is 0b0100 (CNF configured as floating input, MODE configured as input). We want to change it into output. First, we set MODE to anything non-zero (different speeds of output), such as 0b01. Note that the reset value of the registers in question is NOT all zeroes as per reference manual. Some bits are set upon boot, so you need to take extra care with that (such as clearing field bits before setting them).
If you don't want to bother with generalizing the code for an arbitrary pin number, you can do it manually for just this one pin:
This one line sets Pin 13 as GPIO output. First I clear both fields at the same time, then write the new value for the MODE, while CNF stays zeroed out (which is our intention).
Your code should look closer to this then:
Also, main() should never return. Otherwise the CPU crashes, and everything is reset to reset state (makes GPIO inputs). Hence while(1) at the end.
Additionally, you don't have to allocate pointers at all, you can use macros that you cast to pointers and dereference all on one line, if you wish so.
EDIT: all registers need to be used as volatiles. So it's (volatile uint32_t*) - pointers to volatile integers, because the contents of the registers may change outside the main CPU thread (by interrupts or by MCU itself during its own stuff), for example registers that contain flags have them set by MCU. You want the compiler to force the thread to retrieve the freshest value from the register whenever you request it, and not use the value that got stored in the internal CPU registers, because it could be outdated. More on volatiles: Why is a point-to-volatile pointer, like "volatile int * p", useful? StackOverflow