#include "stm32f10x.h"
#include "_HAL_GPIO.h"
GPIO_TYPE ledGPIO;
GPIO_TYPE inputPin;
int main(void){
// Configuring GPIO
ledGPIO.port = PORTC;
ledGPIO.pin = 13;
ledGPIO.mode = OUTPUT_MODE;
ledGPIO.mode_type = OUTPUT_GEN_PURPOSE;
ledGPIO.speed = SPEED_50MHZ;
gpio_init(ledGPIO);
inputPin.port = PORTB;
inputPin.pin = 3;
inputPin.mode = INPUT_MODE;
inputPin.mode_type = INPUT_PU_PD;
gpio_init(inputPin);
inputPin.port -> ODR |= (1 << inputPin.pin); // Setting pull up
while(1) {
gpio_write(ledGPIO.port, ledGPIO.pin, LOW);
for ( int i = 0; i <= 5000000; i++);
gpio_write(ledGPIO.port, ledGPIO.pin, HIGH);
for ( int i = 0; i <= 5000000; i++);
}
}
What hardware, a "known good" like Nucleo ro Disco, or your own? In the latter case, is there anything connected to that pin?
RCC->AHB1ENR |= 0x6; // Enable GPIO B and C
The code you posted is missing a lot of information.
You state to have written wrappers to make life easy, but not showing that code makes it harder for us to say what could be wrong.
What I don't get is why you made a structure for holding the information of a GPIO and then not pass that struct to your gpio_write function, but that is not why the code is failing of course.
//----------------------------------------------------------------------------------------------------------------------------------
//Simple function for setup of an IO pin
void InitIOPin(GPIO_TypeDef *port, uint32_t pin, uint32_t mode, uint32_t conf)
{
//Mix the mode and configuration for single instruction usage
uint32_t data = mode | (conf << 2);
//Create a base pointer for either the lower or the higher control register
__IO uint32_t *reg;
//See if the lower control register or the higher control register needs to be used
if(pin < 8)
{
//Low control register used for first 8 pins
reg = &port->CRL;
}
else
{
//Force pin into 8 pins per register range
pin -= 8;
//High control register used for upper 8 pins
reg = &port->CRH;
}
//4 control bits used per pin
pin *= 4;
//Reset bits first and set new mode and configuration.
*reg &= ~(0x0F << pin);
*reg |= (data << pin);
}
//----------------------------------------------------------------------------------------------------------------------------------
uint32_t readIOPin(GPIO_TypeDef *port, uint32_t pin)
{
//Convert pin number to a bit mask
register uint32_t mask = (1 << pin);
//Get the masked status of the pin and match it with the mask to return either 0 or 1
return((port->IDR & mask) == mask);
}
//----------------------------------------------------------------------------------------------------------------------------------
void setIOPin(GPIO_TypeDef *port, uint32_t pin)
{
//Convert pin number to a set bit mask and set the output
port->ODR |= (1 << pin);
}
//----------------------------------------------------------------------------------------------------------------------------------
void clearIOPin(GPIO_TypeDef *port, uint32_t pin)
{
//Convert pin number to a clear bit mask and clear the output
port->ODR &= ~(1 << pin);
}
//----------------------------------------------------------------------------------------------------------------------------------
you're needs to configure clock and enable clock for GPIO port
void gpio_init (GPIO_TYPE gpio_type){
if(gpio_type.port == PORTA)
GPIO_CLOCK_ENABLE_PORTA;
if(gpio_type.port == PORTB)
GPIO_CLOCK_ENABLE_PORTB;
if(gpio_type.port == PORTC)
GPIO_CLOCK_ENABLE_PORTC;
if(gpio_type.port == PORTD)
GPIO_CLOCK_ENABLE_PORTD;
config_pin(gpio_type.port, gpio_type.pin, gpio_type.mode_type);
config_pin_speed(gpio_type.port, gpio_type.pin, gpio_type.speed, gpio_type.mode);
}
//CLOCK ENABLING
#define GPIO_CLOCK_ENABLE_ALT_FUNC (RCC -> APB2ENR |= ( 1 << 0 ))
#define GPIO_CLOCK_ENABLE_PORTA (RCC -> APB2ENR |= ( 1 << 2 ))
#define GPIO_CLOCK_ENABLE_PORTB (RCC -> APB2ENR |= ( 1 << 3 ))
#define GPIO_CLOCK_ENABLE_PORTC (RCC -> APB2ENR |= ( 1 << 4 ))
#define GPIO_CLOCK_ENABLE_PORTD (RCC -> APB2ENR |= ( 1 << 5 ))
static uint32_t PINPOS[16] = {
(0x00),
(0x04),
(0x08),
(0x0C),
(0x10),
(0x14),
(0x18),
(0x1C),
(0x00),
(0x04),
(0x08),
(0x0C),
(0x10),
(0x14),
(0x18),
(0x1C)
};
static void config_pin (GPIO_TypeDef *port, uint32_t pinNumber, uint32_t mode_type){
if (pinNumber >= 8){ // CONTROL HIGH REGISTER
switch (mode_type)
{
case OUTPUT_GEN_PURPOSE | INPUT_ANALOG:
port -> CRH &= ~(( 1 << CNF_POS_BIT1 ) | ( 1 << CNF_POS_BIT2 ));
break;
case OUTPUT_OD | INPUT_FLOATING:
port -> CRH &= ~( 1 << CNF_POS_BIT2);
port -> CRH |= ~( 1 << CNF_POS_BIT1);
break;
case OUTPUT_ALT_FUNCTION | INPUT_PU_PD:
port -> CRH |= OUTPUT_ALT_FUNCTION << (CNF_POS_BIT1);
break;
case OUTPUT_ALT_FUNCTION_OD:
port -> CRH |= OUTPUT_ALT_FUNCTION_OD << (CNF_POS_BIT1);
break;
}
}
else { // CONTROL LOW REGISTER
switch (mode_type)
{
case OUTPUT_GEN_PURPOSE | INPUT_ANALOG:
port -> CRL &= ~(( 1 << CNF_POS_BIT1 ) | ( 1 << CNF_POS_BIT2 ));
break;
case OUTPUT_OD | INPUT_FLOATING:
port -> CRL &= ~( 1 << CNF_POS_BIT2);
port -> CRL |= ~( 1 << CNF_POS_BIT1);
break;
case OUTPUT_ALT_FUNCTION | INPUT_PU_PD:
port -> CRL |= OUTPUT_ALT_FUNCTION << (CNF_POS_BIT1);
break;
case OUTPUT_ALT_FUNCTION_OD:
port -> CRL |= OUTPUT_ALT_FUNCTION_OD << (CNF_POS_BIT1);
break;
}
}
}
static void config_pin_speed (GPIO_TypeDef *port, uint32_t pinNumber, uint32_t pinSpeed, uint32_t mode){
if (pinNumber >= 8){ // CONTROL HIGH REGISTER
if (mode == INPUT_MODE)
port -> CRH &= ~( 1 << (PINPOS[pinNumber]) | 1 << (PINPOS[pinNumber] + 1));
else
port -> CRH |= (pinSpeed << (PINPOS[pinNumber]));
}
else { // CONTROL LOW REGISTER
if(mode == INPUT_MODE)
port -> CRL &= ~( 1 << (PINPOS[pinNumber]) | 1 << (PINPOS[pinNumber] + 1));
else
port -> CRL |= (pinSpeed << (PINPOS[pinNumber]));
}
}
// INPUT MODES TYPE
#define INPUT_ANALOG ((uint32_t) 0x00)
#define INPUT_FLOATING ((uint32_t) 0x01) // default state at reset
#define INPUT_PU_PD ((uint32_t) 0x02) // input with pullup or pulldown
// OUTPUT MODE TYPE
#define OUTPUT_GEN_PURPOSE ((uint32_t) 0x00) // gerneal purpose output
#define OUTPUT_OD ((uint32_t) 0x01) // output open drain
#define OUTPUT_ALT_FUNCTION ((uint32_t) 0x02) // push pull
#define OUTPUT_ALT_FUNCTION_OD ((uint32_t) 0x03) // open drain
// HIGH BIT POSITION FOR CRH REGISTER CNFYG AND MODE
#define CNF_POS_BIT1 (PINPOS[pinNumber] + 2)
#define CNF_POS_BIT2 (PINPOS[pinNumber] + 3)
PB3 is one of the JTAG pins (TDO). You need to release this pin from that role.
Assuming you are running SWD to debug, you could call
LL_GPIO_AF_Remap_SWJ_NOJTAG();
found in stm32f1xx_ll_gpio.h, then the pin will be usable.
If you really want to learn bare metal programming, forget that youtube channel and download the ST reference manual for the STM32F103 series and start with writing programs writing directly to the registers. When you understand the working of it try to come up with your own abstraction layer to make it easier for future development.
#include "stm32f10x.h"
int main(void){
// Configuring GPIO
RCC -> APB2ENR |= ( 1 << 4 ); // Enabling Clock for Port C
// For Pin C13 - LED
GPIOC -> CRH |= ( ( 1 << 20 ) | ( 1 << 21) ); // Set to 50 MHz Output Mode
GPIOC -> CRH &= ( uint32_t ) ~( ( 1 << 22 ) | ( 1 << 23) ); // Set to General Purpose push-pull
// For Pin C14
GPIOC -> CRH &= ( uint32_t ) ~( ( 1 << 24 ) | ( 1 << 25) ); // Set to Input mode 00
// Set Config to 10
GPIOC -> CRH &= ( uint32_t ) ~( 1 << 26 );
GPIOC -> CRH |= ( 1 << 27 );
GPIOC -> ODR |= ( 1 << 14 ); // Set pin pull up
while(1) {
for ( int i = 0; i <= 1000000; i++) ;
GPIOC -> BSRR = ( 1 << 13 ); // Set Pin C13
for ( int i = 0; i <= 5000000; i++) ;
GPIOC -> BSRR = ( 1 << ( 13 + 16 ) ); // Reset Pin C13
}
}
// Set Config to 10
GPIOC -> CRH &= ( uint32_t ) ~( 1 << 26 );
GPIOC -> CRH |= ( 1 << 27 );
void local_setup(void)
{
/* We will use A1 as a general purpose oscilloscope signal and
* as a trigger for the signal analyzer.
* A0 is the strobe signal for testing with TM1638 LED+keypad.
*/
IO_PIN pin;
pin.gpio = GPIOA;
pin.pin_num = 0;
pin_config(&pin, PIN_OUTPUT | PIN_PUSHPULL | PIN_SPEED_MED);
GPIOA->ODR = 1;
pin.pin_num = 1;
pin_config(&pin, PIN_OUTPUT | PIN_PUSHPULL | PIN_SPEED_MED);
}
I am planning to use libopencm3 for my future experiments, any comments on that will be helpful.
Also, any suggestion on how to do this bit wise operation better.Code: [Select]// Set Config to 10
GPIOC -> CRH &= ( uint32_t ) ~( 1 << 26 );
GPIOC -> CRH |= ( 1 << 27 );
GPIOC->CRH = (GPIOC->CRH & ~(1 << 26)) | (1 << 27); // set CNF to 0b10: Input with pull-up / pull-down
and it can be made somewhat "better" to manipulate the whole bitfield at once, which also reveals the whole you are going to write: GPIOC->CRH = (GPIOC->CRH & ~(0b11 << 26)) | (0b10 << 26); // set CNF to 0b10: Input with pull-up / pull-down
and it can be made yet "better" by emphasizing, that you want to set this field for PC14: GPIOC->CRH = (GPIOC->CRH & ~( 0b11 << (4 * (14 - 8) + 2)) | (0b10 << (4 * (14 - 8) + 2)); // set CNF14 to 0b10: Input with pull-up / pull-down
GPIOC->CRH = 0
// define for other GPIOC pins 0..15 here, otherwise they will be set to Analog mode (MODE=0b00, CNF=0b00
| (0b11 << (4 * (13 - 8) + 0)) // set MODE13 to 0b11: 50MHz output
| (0b00 << (4 * (13 - 8) + 2)) // set CNF13 to 0b00: General purpose output push-pull
| (0b00 << (4 * (14 - 8) + 0)) // set MODE14 to 0b00: Input
| (0b10 << (4 * (14 - 8) + 2)) // set CNF14 to 0b10: Input with pull-up / pull-down
;
That's a mess to maintain and understand.