Store field descriptor constants in flash on AVR (#464)
diff --git a/pb.h b/pb.h
index 91c1e79..871422d 100644
--- a/pb.h
+++ b/pb.h
@@ -127,6 +127,19 @@
 #define PB_UNUSED(x) (void)(x)
 #endif
 
+/* Harvard-architecture processors may need special attributes for storing
+ * field information in program memory. */
+#ifndef PB_PROGMEM
+#ifdef __AVR__
+#include <avr/pgmspace.h>
+#define PB_PROGMEM             PROGMEM
+#define PB_PROGMEM_READU32(x)  pgm_read_dword(&x)
+#else
+#define PB_PROGMEM
+#define PB_PROGMEM_READU32(x)  (x)
+#endif
+#endif
+
 /* Compile-time assertion, used for checking compatible compilation options.
  * If this does not work properly on your compiler, use
  * #define PB_NO_STATIC_ASSERT to disable it.
@@ -448,7 +461,7 @@
 
 /* Binding of a message field set into a specific structure */
 #define PB_BIND(msgname, structname, width) \
-    const uint32_t structname ## _field_info[] = \
+    const uint32_t structname ## _field_info[] PB_PROGMEM = \
     { \
         msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
         0 \
diff --git a/pb_common.c b/pb_common.c
index 4f7e688..8ff9bd1 100644
--- a/pb_common.c
+++ b/pb_common.c
@@ -15,7 +15,7 @@
     if (iter->index >= iter->descriptor->field_count)
         return false;
 
-    word0 = iter->descriptor->field_info[iter->field_info_index];
+    word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
     format = word0 & 3;
     iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
     iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
@@ -31,7 +31,7 @@
     else if (format == 1)
     {
         /* 2-word format */
-        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
+        uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
 
         iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
         iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6));
@@ -42,9 +42,9 @@
     else if (format == 2)
     {
         /* 4-word format */
-        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
-        uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
-        uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
+        uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
+        uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
+        uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
 
         iter->array_size = (pb_size_t)(word0 >> 16);
         iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
@@ -55,10 +55,10 @@
     else
     {
         /* 8-word format */
-        uint32_t word1 = iter->descriptor->field_info[iter->field_info_index + 1];
-        uint32_t word2 = iter->descriptor->field_info[iter->field_info_index + 2];
-        uint32_t word3 = iter->descriptor->field_info[iter->field_info_index + 3];
-        uint32_t word4 = iter->descriptor->field_info[iter->field_info_index + 4];
+        uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
+        uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
+        uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
+        uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
 
         iter->array_size = (pb_size_t)word4;
         iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
@@ -126,7 +126,7 @@
          * - bits 2..7 give the lowest bits of tag number.
          * - bits 8..15 give the field type.
          */
-        uint32_t prev_descriptor = iter->descriptor->field_info[iter->field_info_index];
+        uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
         pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
         pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
 
@@ -159,7 +159,8 @@
     const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
     bool status;
 
-    if (PB_ATYPE(msg->field_info[0] >> 8) == PB_ATYPE_POINTER)
+    uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
+    if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
     {
         /* For pointer extensions, the pointer is stored directly
          * in the extension structure. This avoids having an extra
@@ -199,7 +200,7 @@
             advance_iterator(iter);
 
             /* Do fast check for tag number match */
-            fieldinfo = iter->descriptor->field_info[iter->field_info_index];
+            fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
 
             if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
             {