I have the following function initGPIO. The goal is to enable the GPIOs 0, 1 and 2 on beaglebone using am335x. How can I enable the corresponding GPIO set to the reg_GPIO that are given in the header file? I have the header file GPIO.h which contains the GPIO's numbers, register number and register structure. I have tried to set the GPIO in the function initGPIO. Does it make sense?
gpio.h
#include <stdint.h>
#include <stdbool.h>
#define GPIO0 0 /*!< GPIO 0 number */
#define GPIO1 1 /*!< GPIO 1 number */
#define GPIO2 2 /*!< GPIO 2 number */
#define GPIO3 3 /*!< GPIO 3 number */
// Base address for each gpio hardware module.
#define GPIO0_REG 0x44E07000 //<! gpio0 hardware module address.
#define GPIO1_REG 0x4804C000 //<! gpio1 hardware module address.
#define GPIO2_REG 0x481AC000 //<! gpio2 hardware module address.
#define GPIO3_REG 0x481AE000 //<! gpio3 hardware module address.
// Register Structure
typedef struct
{
volatile uint32_t irqstatus_set_0; // Offset 0x34 - Enables specific interrupt event to trigger.
volatile uint32_t irqstatus_set_1; // Offset 0x38 - Enables specific interrupt event to trigger.
volatile uint32_t irqwaken_0; // Offset 0x44 - Enables wakeup events on an interrupt.
volatile uint32_t irqwaken_1; // Offset 0x48 - Enables wakeup events on an interrupt.
volatile uint32_t ctrl; // Offset 0x130 - Controls clock gating functionality, i.e. enables module.
volatile uint32_t oe; // Offset 0x134 – Output Enable pin (clear bit to 0) output capability.
volatile uint32_t datain; // Offset 0x138 - Registers data read from the GPIO pins.
volatile uint32_t dataout; // Offset 0x13c - Sets value of GPIO output pins.
volatile uint32_t cleardataout; // Offset 0x190 - Clears to 0 bits in dataout
volatile uint32_t setdataout; // Offset 0x194 - Sets to 1 bits in dataout
} GPIO_REGS;
void initGPIO();
gpio.c
/*!
* \brief Initialize GPIOs.
*
* Enables GPIO0, GPIO1, and GPIO2 (GPIO3 not used in IDP. Also configures the output pins
* used in the IDP to control relays and address the ADC's on relays.
*
*****************************************************************************************/
void initGPIO()
{
//enable GPIOs
GPIO_REGS gpio_regs;
//might need to change ctrl
gpio_regs.datain |= (GPIO0 << GPIO0_REG );
gpio_regs.datain |= (GPIO1 << GPIO1_REG );
gpio_regs.datain |= (GPIO2 << GPIO2_REG );
}
By default Beaglebones come with Debian Linux. Unless you've decided to drop that, the kernel has a GPIO driver which assumes control of all GPIO. You should not try to access raw GPIO registers directly, but rather talk to the kernel driver. The simplest way to do that is to install libgpiod (which may be installed by default on recent Beagles) and call its API.
For bare bone platforms you may be used to do something like this to access hardware addresses:
volatile GPIO_REGS* gpio1_regs = (GPIO_REGS*)0x44E07000;
volatile GPIO_REGS* gpio2_regs = (GPIO_REGS*)0x4804C000;
Now your code isn't doing this either, but I'm going to assume that is what you meant.
Except inside an OS the memory offsets in you user-space application don't map one-on-one to hardware address offsets and this simply won't work.
If you want direct register access to things like this, you'll have to do something like Memory Mapping using /dev/mem or if your platform supports it, /dev/gpiomem (I know Raspberry Pi supports this, I'm not sure about the BBB). This will check if you are allowed to access the hardware address range you want, as well as make sure the address range is mapped correctly in your user-space.
For example:
/* open /dev/mem */
int fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd >= 0) {
/* mmap GPIO */
volatile GPIO_REGS* gpio1_regs = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x44E07000);
close(fd); /* No need to keep fd open after mmap */
/* Check for MAP_FAILED error */
if (gpio1_regs != (GPIO_REGS*)-1) {
/* Do whatever */
(The last argument to mmap is where you place your hardware address, I'm using 0x44E07000 in this example.)
For further reading, see also:
https://man7.org/linux/man-pages/man2/mmap.2.html
https://pagefault.blog/2017/03/14/access-hardware-from-userspace-with-mmap/
Related
So I've been scouring the internet for an answer and have not gotten anywhere.
What I want to know is if struct-style register definitions for microcontrollers (ARM mcu, AVR mcu) consume RAM. I know that if an object of a struct is instantiated it will consume RAM (either on the stack or otherwise).
But what about register definitions like the ones below, that are used by ARM in their CMSIS and similar to what the new ATTiny series use for their register definitions as far as I know.
Do these consume RAM memory specifically. I'm quite sure they would somewhat consume flash/program space, but RAM?
#define PORT ((Port *)0x41008000UL) /**< \brief (PORT) APB Base Address */
typedef struct {
PortGroup Group[4]; /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
} Port;
typedef struct {
__IO PORT_DIR_Type DIR; /**< \brief Offset: 0x00 (R/W 32) Data Direction */
__IO PORT_DIRCLR_Type DIRCLR; /**< \brief Offset: 0x04 (R/W 32) Data Direction Clear */
__IO PORT_DIRSET_Type DIRSET; /**< \brief Offset: 0x08 (R/W 32) Data Direction Set */
__IO PORT_DIRTGL_Type DIRTGL; /**< \brief Offset: 0x0C (R/W 32) Data Direction Toggle */
__IO PORT_OUT_Type OUT; /**< \brief Offset: 0x10 (R/W 32) Data Output Value */
__IO PORT_OUTCLR_Type OUTCLR; /**< \brief Offset: 0x14 (R/W 32) Data Output Value Clear */
__IO PORT_OUTSET_Type OUTSET; /**< \brief Offset: 0x18 (R/W 32) Data Output Value Set */
__IO PORT_OUTTGL_Type OUTTGL; /**< \brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
__I PORT_IN_Type IN; /**< \brief Offset: 0x20 (R/ 32) Data Input Value */
__IO PORT_CTRL_Type CTRL; /**< \brief Offset: 0x24 (R/W 32) Control */
__O PORT_WRCONFIG_Type WRCONFIG; /**< \brief Offset: 0x28 ( /W 32) Write Configuration */
__IO PORT_EVCTRL_Type EVCTRL; /**< \brief Offset: 0x2C (R/W 32) Event Input Control */
__IO PORT_PMUX_Type PMUX[16]; /**< \brief Offset: 0x30 (R/W 8) Peripheral Multiplexing */
__IO PORT_PINCFG_Type PINCFG[32]; /**< \brief Offset: 0x40 (R/W 8) Pin Configuration */
RoReg8 Reserved1[0x20];
} PortGroup;
NOTE : All the code provided in the code blocks above are direct quotes from a user on EEVBlog. It is regarding register definitions provided in CMSIS. Link is here.
EDIT : I understand that MCUs have registers and accessing those registers don't consume RAM. But my confusion is in the way these registers are being referred to. For example :
// if a register address is 0x50
#define address 0x50 // This consumes no RAM as it is resolved during compilation
uint8_t addr = 0x50; // This consumes RAM because it is now a variable
// So what about this??
typedef struct {
uint8_t addr = 0x50;
} address_group;
So accessing the registers themselves won't use up RAM space, but the method we use to easily refer to those addresses, in this case using structs, is what I'm confused about.
All registers can be #define'd one by one which will consume no RAM, but the choice of doing it in struct format...?
In order to control peripherals such as GPIO and UART, the peripherals provide registers that are mapped into the memory address space of the MCU.
The typical address range for such registers on STM32 MCUS is from 0x40000000 upwards. This is separate from both flash and RAM.
As an example: The baud rate register for USART1 might be at address 0x41006008. So by reading a word (32 bit) from that address, the baud rate can be read. And by writing to the address, it can be changed.
In C, it could look like:
*(volatile uint32_t*)0x41006008 = 115200;
However, it's much more readable and efficient if it looks like so:
USART1.BRR = 115200;
All the defines and typedefs shown in your question declare data types (such as PortGroup) and pseudo variables (such as PORT). I call them pseudo because they are not regular variables allocated in RAM but rather memory mapped structures built into hardware. (And data type declaration never consume memory anyway.)
The neat thing about this approach is: the code is easier to write and read and still the same size as the cryptic code. It's resolved at compile time as the compiler can figure out the absolute address of USART1.BRR.
Strictly speaking, memory-mapped registers are RAM, in a way, though they can be updated by hardware and software both. They are located in the memory map at a location where the linker isn't allowed to mess around. The compiler in general has no awareness that the register area exists.
By using methods like those described here: How to access a hardware register from firmware? , or by using a pre-made "register map" from the vendor, we tell the compiler to access an area of memory where it has no clue what's stored.
You can tell the compiler for example "there's a PortGroup struct at this location, from address 0x41008000UL and beyond". The compiler then blindly trusts the programmer and accesses that area through the pointer provided, using the declared types of the struct. If these types matches the hardware registers, then everything will work just as if you had allocated variables there. But you actually don't need to have make the linker allocate memory in that area, because everything is already provided in the hardware.
Accessing the registers, or accessing any other form of variable for that matter, doesn't necessarily take any RAM. Given any random variable int x;, then x itself is allocated somewhere, but the act of accessing it with x=0; etc doesn't likely take any RAM.
And finally some misconceptions: #define address 0x50 doesn't consume any RAM, not because it is resolved at compile-time, but because it consumes ROM instead. All numbers used by the program will be allocated somewhere in the executable.
If you have uint8_t addr = 0x50; ... if(addr == something), the optimizing compiler does not necessarily have to allocate RAM space for addr. It could optimize away the whole variable. See this example for x86: https://godbolt.org/z/KroKhq. It didn't make any sense to allocate the variable so the compiler stored the magic number 0x50 (80 dec) in the machine code, as part of the cmp instruction. You will get identical machine code if you use #define in the same example.
No, those structures don't take up RAM. RAM is consumeed when you actually define a variable, with code like this
unsigned int myInteger; // takes RAM
struct foo myStruct; // takes RAM
Lines like the ones above tell your compiler/linker to make symbols called myInteger and myStruct and allocate space for those symbols in the RAM area of your microcontroller (possibly on your stack).
On the other hand, when you define a struct type or make a typedef, that is different from defining a variable, and it doesn't take up any RAM:
struct foo { // Does not take RAM, just defines a type.
...
};
When you define a pointer to a struct using the code below, you are just defining an expression that evaluates to a pointer to a struct that already exists in the hardware. You aren't doing anything that should consume RAM:
// Does not take up RAM, just defines an expression.
#define PORTA ((struct GPIO *)0x1230)
When you use PORTA in your code, the lines of code that use it will take some code space. Those lines might take some stack space when they execute, but they should not take up any RAM permanently.
From stm32f446xx.h we have a definition of GPIO_TypeDef
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
This is used to initialize some GPIO peripherals. Focusing on GPIOA:
#define PERIPH_BASE ((uint32_t)0x40000000)
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
So my questions are:
Is the #define directive declaring and initializing the struct and putting it at address pointed to at `GPIOA_BASE? Or is the define statement just declaring the struct but not initializing its members?
How do the members get their address placement correct without it being explicitly defined? How do we know that GPIOA->MODER leads to the same address as GPIOA_BASE? Likewise how do we know GPIOA->ODR leads to the address GPIOA_BASE + offset 0x014? Is it simply because when we declare the struct and tell it that it's located at GPIOA_BASE with the #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) command all it's member variables are declared and initialized in memory in the order they appear in the struct GPIOA_TypeDef? That would make sense since each takes 4 bytes but I am unsure if this is the case.
If the member variables are not declared in the order they are listed in the struct then how do they get their memory addresses assigned?
The name "C" is used to describe two things:
A family of languages which map source code constructs onto target-machine constructs in a rather consistent fashion. There's often no "standard" documenting how such mapping should be performed, and implementations for unusual target platforms will behave differently from those for more common ones, but compilers for similar platforms will generally behave similarly.
A language which contains only the features mandated by the C11 Standard, and generally omits features which aren't implemented consistently on all platforms, even though C compilers for similar platforms would have processed them similarly.
The code you cite above is designed for compilers that process a languages in the first family, which is adapted to the needs of ARM processors. In that language, each item of a structure will be placed at the lowest offset which satisfies its alignment requirement. Neither the C11 Standard, nor any of its predecessors, requires that compilers guarantee to lay out structures in such fashion, nor do any of them even any convenient way for those that sometimes do otherwise to indicate that fact. From the point of view of the C11 Standard, structure elements may be arbitrarily placed subject subject to relatively few constraints. I think the authors of C89 probably figured that compiler writers would lay things out sequentially, with or without a mandate, except on rare platforms where there might be a compelling reason to do otherwise, and thus saw no reason to demand that they behave as they were going to anyway. Some people, however, seem to believe the lack of a mandate was meant to be an open invitation to arrange things arbitrarily, and any code that would rely upon a particular layout should be viewed as "defective".
I am using bit banding to set and clear a GPIO6[1] of LPC1857 using Keil.
The mapping address in bit band region to set GPIO6[1] comes 0x43EC4304
The mapping address in bit band region to clear GPIO6[1] comes 0x43EC5384
THE GPIO gets set successfully but does not get cleared.
When checked on debugger, it is observed that mapping address to clear the GPIO6[1] was getting set to 0x43EC5000. Thus the GPIO does not get clear.
Can someone please help understand why this is happening ?
And how can I resolve this mapping address setting to wrong address at run time ?
Following is code snippet:
/*In "main.c"*/
int main()
{
... //System initialization
... //GPIO init
...
Toggle_Peri();
}
/*In "Peri.c"*/
/* Bit band PERIPHERAL definitions */
#define BITBAND_PERI_REF 0x40000000 //Start Address of PeripheRALS
#define BITBAND_PERI_BASE 0x42000000 //Start Address of Peripheral Bit Band Alias Region
/* Basic bit band function definition */
#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + ((a-BITBAND_PERI_REF)*(0x20)) + (b*(0x04)))) // Convert GPIO address
#define BITBAND_PERI_SetClearBit(a,b) ((*(volatile uint32_t *) (BITBAND_PERI(a,b))) = 1)
/*Note: Base Address of GPIO = 0x400F 4000*/
#define PERI_GPIO_ADDRESS_S 0x400F6218 //For GPIO6[1] set
#define PERI_GPIO_ADDRESS_C 0x400F629C //For GPIO6[1] clear
#define PERI_GPIO_BIT 1
...
...
...
...
void Toggle_Peri(void)
{
BITBAND_PERI_SetClearBit(PERI_GPIO_ADDRESS_S,PERI_GPIO_BIT); //Set the pin
Delay(0xFFFF);
BITBAND_PERI_SetClearBit(PERI_GPIO_ADDRESS_C,PERI_GPIO_BIT); //Clear the pin
Delay(0xFFFF);
}
I'm working on a developing board that has a 32-bit ARM based microntroller on it (namely the board is Atmel SAM D21J18A). I'm still at the learning phase and I have a lot to go, but I'm really into embedded systems.
I have some background in C. However, it's obviously not enough. I was looking at the codes of an example project by Atmel, and I didn't really get some parts of it. Here is one of them:
#define PORT ((Port *)0x41004400UL) /**< \brief (PORT) APB Base Address */
Port is defined as:
typedef struct {
PortGroup Group[2]; /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
} Port;
and PortGroup is defined as:
typedef struct {
__IO PORT_DIR_Type DIR; /**< \brief Offset: 0x00 (R/W 32) Data Direction */
__IO PORT_DIRCLR_Type DIRCLR; /**< \brief Offset: 0x04 (R/W 32) Data Direction Clear */
__IO PORT_DIRSET_Type DIRSET; /**< \brief Offset: 0x08 (R/W 32) Data Direction Set */
__IO PORT_DIRTGL_Type DIRTGL; /**< \brief Offset: 0x0C (R/W 32) Data Direction Toggle */
__IO PORT_OUT_Type OUT; /**< \brief Offset: 0x10 (R/W 32) Data Output Value */
__IO PORT_OUTCLR_Type OUTCLR; /**< \brief Offset: 0x14 (R/W 32) Data Output Value Clear */
__IO PORT_OUTSET_Type OUTSET; /**< \brief Offset: 0x18 (R/W 32) Data Output Value Set */
__IO PORT_OUTTGL_Type OUTTGL; /**< \brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
__I PORT_IN_Type IN; /**< \brief Offset: 0x20 (R/ 32) Data Input Value */
__IO PORT_CTRL_Type CTRL; /**< \brief Offset: 0x24 (R/W 32) Control */
__O PORT_WRCONFIG_Type WRCONFIG; /**< \brief Offset: 0x28 ( /W 32) Write Configuration */
RoReg8 Reserved1[0x4];
__IO PORT_PMUX_Type PMUX[16]; /**< \brief Offset: 0x30 (R/W 8) Peripheral Multiplexing n */
__IO PORT_PINCFG_Type PINCFG[32]; /**< \brief Offset: 0x40 (R/W 8) Pin Configuration n */
RoReg8 Reserved2[0x20];
} PortGroup;
So here, we are looking at the address 0x41004400UL, get the data in there, and then what happens?
I looked up for this but couldn't find anything useful. If you have any suggestions (tutorials, books etc.), please let me hear.
Nothing happens, because you only present some declarations. I'm not entirely sure what the question actually is, but to briefly explain that code:
0x41004400UL is obviously an address in I/O space (not regular memory) where a port starts (a set of I/O registers)
This Port consists of two groups with a similar arrangement of single registers
struct PortGroup models these registers exactly in the layout present on the hardware
To know the meaning of the Registers, look up the hardware documentation.
Generally you can access a hardware register in C in this manner:
#define PORT (*(volatile uint8_t*)0x1234)
0x1234 is the register address
uint8_t is the type of the register, in this case 1 byte large.
volatile is required so that the compiler knows it cannot optimize such a variable, but that each read or write to the variable stated in the code must actually be done.
(volatile uint8_t*) casts the integer literal to an address of the desired type.
The left-most * then take the contents of that address, so that the macro can be used just as if PORT was a regular variable.
Note that this does not allocate anything! It just assumes that there is a hardware register present at the given address, which can be accessed by the type specified (uint8_t).
Using the same method you can also have other C data types to correspond directly hardware registers. For example by using a handy struct, you can map the whole register area of a particular hardware peripheral. Such code is however a bit dangerous and questionable, since it must take things like alignment/struct padding and aliasing in account.
As for the specific code in your example, it is a typical awful register map for a particular hardware peripheral (looks like a plain general-purpose I/O port) on a certain microcontroller. One such beast is typically provided with each compiler supporting the MCU.
Such register maps are sadly always written in awful, completely non-portable ways. For example, two underscores __ is a forbidden identifier in C. Neither the compiler nor the programmer is allowed to declare such identifiers (7.1.3).
What's really strange is that they have omitted the volatile keyword. This means that you have one of these scenarios here:
The volatile keyword is hidden beneath the Port definition. Most likely this is the case, or
The register map is full of fatal bugs, or
The compiler is such an awful piece of crap that it doesn't optimize variables at all. Which would make the issues with volatile go away.
I would investigate this further.
As for struct padding and aliasing, the compiler vendor has likely implicitly assumed that only their compiler is to be used. They have no interest in providing you with a portable register map, so that you can switch the the competitor's compiler for the same MCU.
I have just started to explore the CMSIS for ARM controllers. It seems rather convenient to use it, however I was wondering where are the actual register values defined. Let's just take for example the GPIOs.
There is a structure GPIOA_AHB_Type defined with various members. Then, for GPIOB, there is a memory (or register?) address defined, let's say GPIOB_AHB_BASE. Afterwards, a pointer is set to GPIOB_AHB_BASE, like this:
#define GPIOB_AHB ((GPIOA_AHB_Type*) GPIOB_AHB_BASE)
GPIOB_AHB's member variables as GPIOB_AHB->DIR for example, to set it input or output. My question is, where precisely are these member variables initialized? I guess the actual address of the registers is device specific, so I tried to find them in the device specific header, but all I found was the GPIOB_AHB_BASE define and the declaration of the member variables. How does the compiler know that when I type GPIOB_AHB->DIR, I want to write into the register that sets that port's I/O direction?
If you look in your CMSIS header, you'll see all the structure definitions. Here's an example from my current project:
typedef struct
{
__IO uint32_t DATA; /*!< Port A Data Register */
__IO uint32_t CR; /*!< Port A Output Control Register */
__IO uint32_t FR1; /*!< Port A Function Register 1 */
__IO uint32_t FR2; /*!< Port A Function Register 2 */
uint32_t RESERVED0[6];
__IO uint32_t OD; /*!< Port A Open Drain Control Register */
__IO uint32_t PUP; /*!< Port A Pull-up Control Register */
uint32_t RESERVED1[2];
__IO uint32_t IE; /*!< Port A Input Control Register */
} TSB_PA_TypeDef;
Later on, a pointer to a structure of that type is defined:
#define PERI_BASE (0x40000000UL)
#define TSB_PA_BASE (PERI_BASE + 0x00C0000UL)
#define TSB_PA (( TSB_PA_TypeDef *) TSB_PA_BASE)
So that you can use it like:
TSB_PA->CR |= (1U << 2); // make Port A, bit 2 an output
value = TSB_PA->DATA & (1U << 5); // read Port A, bit 5.