Reputation: 1115
I know that port mapped IO are accessed thorugh in/out CPU instructions and memory (& memory mapped registers) are accessed through load/store CPU instructions (similar to memory). But, with a pointer in C code, how compiler knows if a address is port mapped IO register or memory and then inserts the correct CPU instructions?
Example:
uint16_t const* uart_reg = 0x8000c000;
uint16_t const* ram_addr = 0x4000c000;
*uart_reg = 0x1;
*ram_addr = 0x12;
Upvotes: 2
Views: 1059
Reputation: 67546
Two steps:
For example if you want to program ARM STM uC bare metal gcc compiler - use arm-none-eabi-gcc
and tools. Use header CMSIS header files provided by STM & ARM (usually they are already included if you choose a "ready made" toolchain)
Example declarations and definitions (only for ADC1):
#define FLASH_BASE ((uint32_t)0x08000000U) /*!< FLASH base address in the alias region */
#define CCMDATARAM_BASE ((uint32_t)0x10000000U) /*!< CCM(core coupled memory) data RAM base address in the alias region */
#define SRAM_BASE ((uint32_t)0x20000000U) /*!< SRAM base address in the alias region */
#define PERIPH_BASE ((uint32_t)0x40000000U) /*!< Peripheral base address in the alias region */
#define SRAM_BB_BASE ((uint32_t)0x22000000U) /*!< SRAM base address in the bit-band region */
#define PERIPH_BB_BASE ((uint32_t)0x42000000U) /*!< Peripheral base address in the bit-band region */
#define AHB3PERIPH_BASE (PERIPH_BASE + 0x10000000U)
#define ADC1_BASE (AHB3PERIPH_BASE + 0x00000000U)
#define ADC1 ((ADC_TypeDef *) ADC1_BASE)
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
typedef struct
{
__IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */
__IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */
__IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */
__IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */
uint32_t RESERVED0; /*!< Reserved, 0x010 */
__IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */
__IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */
uint32_t RESERVED1; /*!< Reserved, 0x01C */
__IO uint32_t TR1; /*!< ADC watchdog threshold register 1, Address offset: 0x20 */
__IO uint32_t TR2; /*!< ADC watchdog threshold register 2, Address offset: 0x24 */
__IO uint32_t TR3; /*!< ADC watchdog threshold register 3, Address offset: 0x28 */
uint32_t RESERVED2; /*!< Reserved, 0x02C */
__IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */
__IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */
__IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */
__IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */
__IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */
uint32_t RESERVED3; /*!< Reserved, 0x044 */
uint32_t RESERVED4; /*!< Reserved, 0x048 */
__IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */
uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */
__IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */
__IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */
__IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */
__IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */
uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */
__IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */
__IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */
__IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */
__IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */
uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */
__IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */
__IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */
uint32_t RESERVED8; /*!< Reserved, 0x0A8 */
uint32_t RESERVED9; /*!< Reserved, 0x0AC */
__IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xB0 */
__IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xB4 */
} ADC_TypeDef;
and it expands to: ((ADC_TypeDef *) ((((uint32_t)0x40000000U) + 0x10000000U) + 0x00000000U))
It is not worth to do it manually.
Upvotes: -1
Reputation: 399843
If you have non-memory-mapped I/O, you're not going to be able to access it from C as if it were memory.
You must use some platform-specific trickery to get the proper I/O instructions. This is a pain, and might be one reason why modern hardware seems to favor memory-mapped I/O.
C compilers for platforms with port-mapped I/O had to include this, see for instance the inp()
function in the old Turbo C++ for DOS.
Upvotes: 4