This may strike some as overkill or redundancy given what ST provide in their various libraries, but I've been getting slightly frustrated at the weak use of intellisense when experimenting with these devices.
The large number of register flag constants seem to be represented as raw #define statements which appear in the global namespace, and coding relies on prefixes for setting register fields, for example RCC_
For example to enable GPIOA clocks we code:
I want instead to be able to rely less on memory and intimate familiarity when coding stuff like this, so I devised this as an experiment:
This then allows me to code the same thing like this:
And because the fields are struct members we get intellisense:
I don't think we can get this kind of intellisense support in the existing libraries (unless perhaps we use HAL or some richer API, which may be undesirable for some needs).
Just by working like this for a short time we begin to get deep insights into what each register provides.
As I say, I'm just experimenting but the sheer number of registers and fields within them is daunting and the lack of namespaces (which is all these structs are doing really) makes even simple experimentation slow going...
Thoughts?
The large number of register flag constants seem to be represented as raw #define statements which appear in the global namespace, and coding relies on prefixes for setting register fields, for example RCC_
For example to enable GPIOA clocks we code:
Code:
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
Code:
typedef struct
{
const uint32_t ENABLE_OTGHSULPI;
const uint32_t ENABLE_OTGHS;
const uint32_t ENABLE_ETHMACPTP;
const uint32_t ENABLE_ETHMACRX;
const uint32_t ENABLE_ETHMACTX;
const uint32_t ENABLE_ETHMAC;
const uint32_t ENABLE_DMA_2;
const uint32_t ENABLE_DMA_1;
const uint32_t ENABLE_CCM_DATA_RAM;
const uint32_t ENABLE_BKP_SRAM;
const uint32_t ENABLE_CRC;
const uint32_t ENABLE_GPIOI_CLOCK;
const uint32_t ENABLE_GPIOH_CLOCK;
const uint32_t ENABLE_GPIOG_CLOCK;
const uint32_t ENABLE_GPIOF_CLOCK;
const uint32_t ENABLE_GPIOE_CLOCK;
const uint32_t ENABLE_GPIOD_CLOCK;
const uint32_t ENABLE_GPIOC_CLOCK;
const uint32_t ENABLE_GPIOB_CLOCK;
const uint32_t ENABLE_GPIOA_CLOCK;
} AHB1ENR_FLAGS;
extern AHB1ENR_FLAGS AHB1ENR =
{
// reserved 1 bit1
1 << 30,
1 << 29,
1 << 28,
1 << 27,
1 << 26,
1 << 25,
// reserved 2 bits
1 << 22,
1 << 21,
1 << 20,
// reserved 1 bits
1 << 18,
// reserved 5 bits
1 << 12,
// reserved 3 bits
1 << 8,
1 << 7,
1 << 6,
1 << 5,
1 << 4,
1 << 3,
1 << 2,
1 << 1,
1 << 0
};
Code:
RCC->AHB1ENR |= AHB1ENR.ENABLE_GPIOA_CLOCK;
I don't think we can get this kind of intellisense support in the existing libraries (unless perhaps we use HAL or some richer API, which may be undesirable for some needs).
Just by working like this for a short time we begin to get deep insights into what each register provides.
As I say, I'm just experimenting but the sheer number of registers and fields within them is daunting and the lack of namespaces (which is all these structs are doing really) makes even simple experimentation slow going...
Thoughts?