Accessing Microcontroller Registers
Microcontroller programming requires efficient techniques for register access. Registers are used to configure the CPU and peripheral hardware devices such as flash access, clocks, I/O ports, timers, communication interfaces (UART, SPITM, CAN [1]), etc. T
- PDF / 145,816 Bytes
- 10 Pages / 439.36 x 666.15 pts Page_size
- 79 Downloads / 318 Views
Accessing Microcontroller Registers
Microcontroller programming requires efficient techniques for register access. Registers are used to configure the CPU and peripheral hardware devices such as flash access, clocks, I/O ports, timers, communication interfaces (UART, SPITM , CAN [1]), etc. This chapter describes C++ methods that can be used to manipulate microcontroller registers. The focus of this chapter is placed on template methods that provide for efficient, scalable and nearly portable register access.
7.1 Defining Constant Register Addresses C programmers often define register addresses with a preprocessor #define. For example,
// The 8-bit address of portb. #define REG_PORTB ((uint8_t) 0x25U) The preprocessor symbol REG_PORTB represents the 8–bit address of portb on our target with the 8–bit microcontroller. We first encountered this register in the LED program of Sect. 1.1. The value of portb’s address is 0x25. The type of the address is uint8_t. In addition, the type information is tightly bound to the preprocessor definition with a C-style cast operator. All-in-all, this is a robust register definition in C. As mentioned in association with the LED program in Sect. 1.10, portb can also be manipulated via direct memory access in the C language. For example, the following C code sets the value of portb to zero.
// Set portb to 0. *((volatile uint8_t*) REG_PORTB) = 0U;
C.M. Kormanyos, Real-Time C++, DOI 10.1007/978-3-642-34688-0__7, © Springer-Verlag Berlin Heidelberg 2013
127
128
7 Accessing Microcontroller Registers
In C++ it can be convenient to define register addresses with compile-time constant static integral members of a class type (such as a structure) or using the constexpr keyword. This technique has already been used a few times in this book and is described in greater detail in Sect. 4.10. In particular, namespace mcal { struct reg { static constexpr std::uint8_t portb = 0x25U;
// Additional registers // ... }; Register addresses can alternatively be defined as compile-time constants with constexpr possibly in a namespace for naming uniqueness. For example, namespace mcal { namespace reg { constexpr std::uint8_t portb = 0x25U;
// Additional registers // ... } }; The mcal::reg structure (or the mcal::reg namespace) can be used to define a variety of microcontroller register addresses. Each register address needed in the program can be included as a compile-time constant. In the mcal::reg structure above, for example, the 8–bit address of portb on our target with the 8–bit microcontroller has a compile-time constant value equal to 0x25. Using the mcal::reg structure (or alternatively the namespace mcal::reg) it is straightforward to set portb via direct memory access in C++. For instance,
// Set portb to 0. *reinterpret_cast (mcal::reg::portb) = 0U; As mentioned in Sects. 1.10 and 4.10, compile-time constants are just as efficient as preprocessor #defines, but have superior type information. Compile-time
7.2 Using Templates for Register Access
129
constants are well-suited for de
Data Loading...