简体   繁体   中英

Is it possible to read and/or write ports via a C variable instead of using GPIO_Pin_N values?

All the sample code I can find accesses ports like so:

GPIO_SetBits(GPIOE, GPIO_Pin_9 | GPIO_Pin_13);

Which looked OK at first, until I tried to reference LEDs (my port E) by index (0-7). A switch or a LUT is a solution, but I don't like either. Is it possible to declare eg uint8_t and map it to the specific range of pins of a certain port?

The standard Cortex-M3/M4 memory map allows for the CPU to have so-called "bit-band" aliases of regions, in which writing to each word in the bit-band alias performs an automatic read-modify-write to alter the target bit in the corresponding region.

Taking the STM32F411 (Cortex-M4F) manual I have to hand as an example, that shows the peripheral region 0x40000000-0x400FFFFF is covered by a bit-band alias in the region 0x42000000-0x43FFFFFF . Thus for instance on that device (if I've got my maths right) each word from 0x42420280-0x42420300 corresponds to a bit in the GPIO port E data register GPIOE_ODR at 0x40021014 , so this:

volatile int *leds = (void *)0x42420280;
leds[x] = 1; /* only bit 0 of the bit-band word actually holds data */

makes the hardware perform the tidily-abstracted equivalent of this:

volatile int *leds = (void *)0x40021014;
int val = *leds;
val |= (1 << x);
*leds = val;

If you have a suitable device, don't want to update multiple bits at once, and don't mind the extra overhead vs. a single access to the regular register in some cases (eg writing the set/clear registers instead of the data), it's a pretty neat trick.

The values of the GPIO_Pin_X constants are defined as bit positions within a 16-bit value, with pin 0 as the least significant bit and pin 15 as the most significant:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
[...]
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */

(This is why you can OR them together to write to multiple pins!)

If you need to index pins dynamically, you can do so using a macro like:

#define GPIO_Pin(x) ((uint16_t) 1 << (x))

busses are fixed width you cannot change that hardware with software, and no you cannot break up a fixed sized register in a peripheral into smaller parts with software. You can possibly make it appear in software to do such a thing but in the end the real code generated by the high level code will still do read-modify-writes or whatever is needed or supported based on bus or peripheral register sized transactions.

Trying to make things smaller even making variables byte sized vs the native size of registers ultimately creates more or inefficient code. So trying to understand why you would want to do such a thing anyway.

An stm32 I recently played with has a bit clear/set register where writing a one clears or sets the output state of a pin. In the logic it simply clears or sets the flip flop controlling that port output, which in logic they can/do implement the backend of a control into smaller parts, but from software you cannot directly access those in non-aligned, not properly sized transfers. Some companies require you, in software, to do a read-modify-write. So using an stm32 with these kinds of features (other brands may also have similar features, sometimes using the address, sometimes like this but in separate registers one for setting one for clearing) actually makes your code about as simple as it can be.

You are more than welcome to create as many defines as you want for combinations of gpio pins so that in your main code you only need one mnemonic instead of multiples orred together if that is your desire.

You do not have to have a function for setting the bits if you can get the compiler to reliably generate a str of the right size, and the right combination if bits in a single define you can simply the code into an a = b; situation.

My guess from your vague question, is a LUT is the optimal solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM