#include <gpio.h> //our gpio related routines
#define LED_PORT GPIOA
#define LED_DDR GPIOA
#define LED ((1<<2) | (1<<3)) //led on pin2 and pin3
PIN_OUT(LED_DDR, LED); //set led as output
PIN_SET(LED_PORT, LED); //set led
PIN_CLR(LED_PORT, LED); //clear led
it does not solve the main problem,
of going through the configuration of all those registers and what is the best way to do it
#define PIN_SET(gpio, pins) gpio->BSRR |= (pins)
#define PIN_SET(port, pins) port->ODR |= (pins)
#define PIN_SET(port, pins) MAP_GPIOPinWrite(port, (pins), (pins))
#define PIN_SET(port, pins) HWREG(port + (GPIO_O_DATA + ((pins) << 2))) = (pins)
#define PIN_SET(port, bits) port |= (bits) //set bits on port
Hi everyone,
i been using microchip for a long time , all family included, most of my project didn't much of processing so 18F family is what i used most. A year ago i started using STM32F0 and god how frustrating that thing is i was like the thing need thousand line to set the input/output
[...] however it does not solve the main problem, of going through the configuration of all those registers and what is the best way to do it, your gpio file will be filled with those infinite line just to tell the damn compiler you need PA0 to be an output
#pragma once
#include "stm32f4xx.h"
#include <cstdint>
#define ALL_PORTS \
PORT(A) \
PORT(B) \
PORT(C) \
PORT(D) \
PORT(E) \
PORT(F) \
PORT(G) \
PORT(H) \
PORT(I)
/*
* The ALL_PINS macro, defined below, contains the I/O pin architecture-
* specific GPIO configuration for the application.
*
* port: GPIOA .. GPIOI
* pin: 0 .. 15
* name: any identifier
* mode: IN | OUT | AN "analog" | AF "alternate function"
* type: PP "push pull" | OD "open drain"
* pupdr: NOPULL | UP | DOWN
* odr: 0 | 1
* af: 0 .. 15
*/
// port, pin, name, mode, type, speed, pupdr, odr, af
#define ALL_PINS \
PIN(GPIOA, 1, DBG_EN, OUT, PP, Low, NOPULL, 0, NONE) \
PIN(GPIOA, 2, FLASH_HOLD, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOA, 3, FLASH_WP, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOA, 4, SPI1_CS, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOA, 5, SPI1_SCK, AF, PP, High, NOPULL, 0, SPI1) \
PIN(GPIOA, 6, SPI1_MISO, AF, PP, High, NOPULL, 0, SPI1) \
PIN(GPIOA, 7, SPI1_MOSI, AF, PP, High, NOPULL, 0, SPI1) \
PIN(GPIOA, 9, USB_VBUS, IN, PP, Low, NOPULL, 0, NONE) \
PIN(GPIOA, 11, USB_N, AF, PP, Low, NOPULL, 0, OTG_FS) \
PIN(GPIOA, 12, USB_P, AF, PP, Low, NOPULL, 0, OTG_FS) \
PIN(GPIOA, 13, SWDIO, AF, PP, High, NOPULL, 0, SWJ) \
PIN(GPIOA, 14, SWCLK, AF, PP, High, NOPULL, 0, SWJ) \
\
PIN(GPIOB, 0, DISP_RES, OUT, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 1, DISP_CS, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOB, 2, BOOT1, IN, PP, Low, NOPULL, 0, NONE) \
PIN(GPIOB, 3, DISP_SCK, AF, PP, High, NOPULL, 0, SPI3) \
PIN(GPIOB, 4, DISP_DC, OUT, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 5, DISP_MOSI, AF, PP, High, NOPULL, 0, SPI3) \
PIN(GPIOB, 10, DBG_TDI, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 11, DBG_TRST, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 12, DBG_SWDIO, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 13, DBG_SWCLK, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 14, DBG_SWO, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOB, 15, DBG_NRST, IN, PP, High, NOPULL, 0, NONE) \
\
PIN(GPIOC, 0, SW3, IN, PP, Low, UP, 0, NONE) \
PIN(GPIOC, 1, SW4, IN, PP, Low, UP, 0, NONE) \
PIN(GPIOC, 2, VCC_SENSE, AN, PP, Low, NOPULL, 0, NONE) \
PIN(GPIOC, 3, SW5, IN, PP, Low, UP, 0, NONE) \
PIN(GPIOC, 7, EN_VCC_USB, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOC, 8, EN_VCC_3V3, OUT, PP, High, NOPULL, 1, NONE) \
PIN(GPIOC, 9, LED1, OUT, PP, High, NOPULL, 0, NONE) \
PIN(GPIOC, 10, DBG_TX, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOC, 11, DBG_RX, IN, PP, High, NOPULL, 0, NONE) \
PIN(GPIOC, 13, LED2, OUT, PP, High, NOPULL, 1, NONE) \
enum all_pins_defs {
#define PIN(port,pin,name,mode,ppod,speed,pull,value,altfn) name = pin,
ALL_PINS
#undef PIN
};
#include "pins.h"
#include "stm32f4xx.h"
#include <cstdint>
struct pin_config_t {
uint32_t periph;
GPIO_TypeDef *port;
GPIO_InitTypeDef init;
uint8_t alternate_fn;
BitAction odr;
};
enum {
GPIO_AF_NONE = 0xff
};
static const pin_config_t pin_config[] = {
#define PIN(port,pin,name,mode,ppod,speed,pull,value,altfn) \
{RCC_AHB1Periph_ ## port, port, {1 << (pin), GPIO_Mode_ ## mode, GPIO_ ## speed ## _Speed, GPIO_OType_ ## ppod, GPIO_PuPd_ ## pull}, GPIO_AF_ ## altfn, (BitAction) value },
ALL_PINS
#undef PIN
};
void configure_gpio_pins() {
GPIO_InitTypeDef unused;
// fill in ST's idea of a default pin
// Note: this may not be correct for lowest power consumption
GPIO_StructInit(&unused);
// Call GPIO_Init() to initialize each port
#define PORT(name) GPIO_Init(GPIO ## name, &unused);
ALL_PORTS
#undef PORT
for(unsigned i=0; i < sizeof(pin_config)/sizeof(pin_config_t); ++i) {
const pin_config_t &config(pin_config[i]);
// enable the port for the pin. OK to do this more than once.
RCC_AHB1PeriphClockCmd(config.periph, ENABLE);
// initialize the pin
GPIO_Init(config.port, (GPIO_InitTypeDef *) &config.init);
// set the altfn
if (config.alternate_fn != GPIO_AF_NONE) {
GPIO_PinAFConfig(config.port, config.init.GPIO_Pin, config.alternate_fn);
}
if (config.init.GPIO_Mode == GPIO_Mode_OUT) {
GPIO_WriteBit(config.port, config.init.GPIO_Pin, config.odr);
}
}
}
Look at the ARM devices from NXP. Simple to use and they keep the same peripherals in future versions.
@andyturk
i will certainty try this code, it's not the "how to" that am asking about really, i just put the gpio as an example of how i find programming STM32 long and annoying, i wanted to see how other developer feel about it, and if anyone have a better approach than the one i use.
the thing is am more in electronic than in coding, i do software certainly for ages, i will not claim that my code is perfect it may look like shit for a trained IT engineer eyes but it work when code is much oriented for ppl that are familiar with C++ developer and such it kind of bores me, and in a way this is what happening here. for the same reason i agree with AndyC about writing your own function that address BSRR directly.
i wanted to see how other developer feel about it, and if anyone have a better approach than the one i use.
Just adding layers (boxing stuff) doesn't make a program more readable.
The nice thing about layering is that the programmer in case of changes/problems does not have to be bothered by the lower (tested) layers and can concentrate on the stuff above.
The nice thing about layering is that the programmer in case of changes/problems does not have to be bothered by the lower (tested) layers and can concentrate on the stuff above.In theory, yes.
In practice... not really.
The nice thing about layering is that the programmer in case of changes/problems does not have to be bothered by the lower (tested) layers and can concentrate on the stuff above.In theory, yes.
In practice... not really.Then maybe you should be looking at your practice because this is all we've got
With regards to hardware design, I can't remember the last time something had been abstracted and tested then went on to fail for me and this failure wasn't down to either:
i) misuse, or
ii) it wasn't properly tested. (copy/paste error in the ALU circuit for an AND operation so bit N of an operand was used instead of bit M (M=/=N) and my insufficient tests missed it).
I'm almost starting to get the feeling some people feel they belong to some elitist group who know how to program ARM controllers and try to keep others out by spreading nonsense about how hard ARM controllers are to work with.
The problem is obvious. You changed the architecture of the hardware, without changing how you write code. If you take 20 years advance there, you should advance here also. I mean ARM is not meant to be programmed with magic numbers to registers. It has CMSIS, and a help file, which is the first place to look at, if you need to configure something. Help file, not the datasheet.
I agree that setting up the develpoment tools is much harder with ARM, and the learning curve is much steeper, but I suspect that it will wash away every 8 bit development in the very near future.
my application was automatically disqualified, they ONLY accept ppl from a local elite IT university here... now i can see why
The biggest problem usually is proper documentation. Without documentation it is much easier to analyse what 2 layers of abstraction are actually supposed to do than to analyse 10 layers of abstration where a lot of layers don't really add anything to the software. Also: with proper documentation it becomes easier to re-use software and less layers means less work on documentation.
If analysing the source of a poorly documented non-working library (=abstraction layer) is the wrong way to move ahead then I'm very curious about your approach in such a situation.