diff --git a/core/include/common_macros.h b/core/include/common_macros.h
index 4aa6248..d4afe4f 100644
--- a/core/include/common_macros.h
+++ b/core/include/common_macros.h
@@ -37,15 +37,71 @@
 #define VAL2FIELD_M(fieldname, value) (((value) & fieldname##_M) << fieldname##_S)
 #define SET_FIELD_M(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD_M(fieldname, value))
 
-/* Use this macro to store constant values in IROM flash instead
-   of having them loaded into rodata (which resides in DRAM)
+/* Use the IRAM macro to place functions into Instruction RAM (IRAM)
+   instead of flash (aka irom).
 
-   Unlike the ESP8266 SDK you don't need an attribute like this for
-   standard functions. They're stored in flash by default. But
-   variables need them.
+   (This is the opposite to the Espressif SDK, where functions default
+   to being placed in IRAM but the ICACHE_FLASH_ATTR attribute will
+   place them in flash.)
 
-   Important to note: IROM flash can only be accessed via 32-bit word
-   aligned reads. It's up to the user of this attribute to ensure this.
+   Use the IRAM attribute for functions which are called when the
+   flash may not be available (for example during NMI exceptions), or
+   for functions which are called very frequently and need high
+   performance.
+
+   Usage example:
+
+   void IRAM high_performance_function(void)
+   {
+       // do important thing here
+   }
+
+   Bear in mind IRAM is limited (32KB), compared to up to 1MB of flash.
+*/
+#define IRAM __attribute__((section(".iram1.text")))
+
+/* Use the RAM macro to place constant data (rodata) into RAM (data
+   RAM) instead of the default placement in flash. This is useful for
+   constant data which needs high performance access.
+
+   Usage example:
+
+   const RAM uint8_t constants[] = { 1, 2, 3, 7 };
+
+   When placing string literals in RAM, they need to be declared with
+   the type "const char[]" not "const char *"
+
+   Usage example:
+
+   const RAM char hello_world[] = "Hello World";
+*/
+#define RAM __attribute__((section(".data")))
+
+/* Use the IRAM_DATA macro to place data into Instruction RAM (IRAM)
+   instead of the default of flash (for constant data) or data RAM
+   (for non-constant data).
+
+   This may be useful to free up data RAM. However all data read from
+   any instruction space (either IRAM or Flash) must be 32-bit aligned
+   word reads. Reading unaligned data stored with IRAM_DATA will be
+   slower than reading data stored in RAM. You can't perform unaligned
+   writes to IRAM.
+*/
+#define IRAM_DATA __attribute__((section(".iram1.data")))
+
+/* Use the IROM macro to store constant values in IROM flash. In
+  esp-open-rtos this is already the default location for most constant
+  data (rodata), so you don't need this attribute in 99% of cases.
+
+  The exceptions are to mark data in the core & freertos libraries,
+  where the default for constant data storage is RAM.
+
+  (Unlike the Espressif SDK you don't need to use an attribute like
+  ICACHE_FLASH_ATTR for functions, they go into flash by default.)
+
+  Important to note: IROM flash is accessed via 32-bit word aligned
+  reads. esp-open-rtos does some magic to "fix" unaligned reads, but
+  performance is reduced.
 */
 #ifdef	__cplusplus
     #define IROM __attribute__((section(".irom0.literal")))
@@ -53,28 +109,5 @@
     #define IROM __attribute__((section(".irom0.literal"))) const
 #endif
 
-/* Use this macro to place functions into Instruction RAM (IRAM)
-   instead of flash memory (IROM).
-
-   This is useful for functions which are called when the flash may
-   not be available (for example during NMI exceptions), or for
-   functions which are called very frequently and need high
-   performance.
-
-   Bear in mind IRAM is limited (32KB), compared to up to 1MB of flash.
-*/
-#define IRAM __attribute__((section(".iram1.text")))
-
-/* Use this macro to place data into Instruction RAM (IRAM)
-   instead of loaded into rodata which resides in DRAM.
-
-   (IRAM can also be written to as necessary.)
-
-   This may be useful to free up data RAM. However all data read from
-   the instruction space must be 32-bit aligned word reads
-   (non-aligned reads will use an interrupt routine to "fix" them and
-   still work, but are very slow..
-*/
-#define IRAM_DATA __attribute__((section(".iram1.rodata")))
 
 #endif
diff --git a/examples/experiments/unaligned_load/unaligned_load.c b/examples/experiments/unaligned_load/unaligned_load.c
index 4244804..ff6cab7 100644
--- a/examples/experiments/unaligned_load/unaligned_load.c
+++ b/examples/experiments/unaligned_load/unaligned_load.c
@@ -13,9 +13,9 @@
 
 #define TESTSTRING "O hai there! %d %d %d"
 
-const char *dramtest = TESTSTRING;
-const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
-const __attribute__((section(".text.notrodata"))) char iromtest[] = TESTSTRING;
+const RAM char dramtest[] = TESTSTRING;
+const char *iromtest = TESTSTRING;
+const IRAM_DATA char iramtest[] = TESTSTRING;
 
 static inline uint32_t get_ccount (void)
 {