Go Down

Topic: Problem accessing large PROGMEM structure (Read 1 time) previous topic - next topic

letaage

Hi,

I'd like to know if there is a practical limit to the size of a data structure (array) you can store in PROGMEM, or if there are any known problems once you get over a certain size.

I am working on a project using a couple of MAX6960 display driver ICs and some 8x8 LED displays.

I'm using the Arduino Diecimila and the hardware SPI interface to talk with the MAX6960 and this all works fine. I am able to write to the display and read back data without a problem.

The display drivers do not have built in character generation hardware so I have created my own font and I've stuck it in PROGMEM.  I've made my custom extended ASCII set from character 1 to 255.  Each character is 8x5 pixels in size, ie 5 bytes of data in a big array of 255 such blocks = 1275 bytes.

The problem I have is getting the data out of PROGMEM, more specifically, I am having a problem accessing data beyond character '\' or character value 92 dec (0x5C).  

Characters '!' to '\' print ok (values 33 dec to 92 dec) but characters after '\' are all offset by 1, ie 'a' prints as 'b' and 'b' prints out as 'c' etc.

For example I have some test code that writes the following string to the display "ab[\]ab" and what comes out is "bc[\^bc".

You can see that all the characters with value greater than '\' are displayed incremented by 1.

I have checked my font data array and it appears correct to me, there are no repeated character blocks.

The entire character set won't fit here but here's how a section looks:

Code: [Select]
prog_uint8_t font_data[END_CHAR - START_CHAR + 1][CHAR_LEN] = {
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   1 SOH
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   2 STX
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   3 ETX
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   4 EOT
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   5 ENQ
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   6 ACK
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   7 BEL
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   8 BS
     {0x00, 0x00, 0x00, 0x00, 0x00}, //   9 HT
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  10 LF
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  11 VT
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  12 FF
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  13 CR
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  14 SO
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  15 SI
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  16 DLE
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  17 DC1
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  18 DC2
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  19 DC3
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  20 DC4
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  21 NAK
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  22 SYN
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  23 ETB
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  24 CAN
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  25 EM
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  26 SUB
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  27 ESC
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  28 FS
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  29 GS
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  30 RS
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  31 US
     {0x00, 0x00, 0x00, 0x00, 0x00}, //  32 SP
     {0x00, 0x00, 0x00, 0x5E, 0x00}, //  33 !
     {0x00, 0x06, 0x00, 0x06, 0x00}, //  34 "
     {0x14, 0x3E, 0x14, 0x3E, 0x14}, //  35 #
     {0x00, 0x24, 0x6A, 0x2B, 0x12}, //  36 $
     {0x4C, 0x2C, 0x10, 0x68, 0x64}, //  37 %
     {0x34, 0x4A, 0x52, 0x24, 0x10}, //  38 &
     {0x00, 0x00, 0x06, 0x00, 0x00}, //  39 '
     {0x00, 0x00, 0x3C, 0x42, 0x00}, //  40 (
     {0x00, 0x00, 0x42, 0x3C, 0x00}, //  41 )
     {0x00, 0x04, 0x0E, 0x04, 0x00}, //  42 *
     {0x08, 0x08, 0x3E, 0x08, 0x08}, //  43 +
     {0x00, 0x00, 0x40, 0x20, 0x00}, //  44 ,
     {0x00, 0x08, 0x08, 0x08, 0x08}, //  45 -
     {0x00, 0x00, 0x00, 0x20, 0x00}, //  46 .
     {0x00, 0x60, 0x18, 0x06, 0x00}, //  47 /
     {0x00, 0x3C, 0x42, 0x42, 0x3C}, //  48 0
     {0x00, 0x00, 0x04, 0x7E, 0x00}, //  49 1
     {0x00, 0x64, 0x52, 0x52, 0x4C}, //  50 2
     {0x00, 0x42, 0x4A, 0x4A, 0x34}, //  51 3
     {0x00, 0x18, 0x14, 0x7E, 0x10}, //  52 4
     {0x00, 0x4E, 0x4A, 0x4A, 0x32}, //  53 5
     {0x00, 0x3C, 0x4A, 0x4A, 0x32}, //  54 6
     {0x00, 0x02, 0x72, 0x0A, 0x06}, //  55 7
     {0x00, 0x34, 0x4A, 0x4A, 0x34}, //  56 8
     {0x00, 0x4C, 0x52, 0x52, 0x3C}, //  57 9
     {0x00, 0x00, 0x00, 0x24, 0x00}, //  58 :
     {0x00, 0x00, 0x40, 0x24, 0x00}, //  59 ;
     {0x00, 0x00, 0x08, 0x14, 0x22}, //  60 <
     {0x00, 0x14, 0x14, 0x14, 0x14}, //  61 =
     {0x00, 0x22, 0x14, 0x08, 0x00}, //  62 >
     {0x00, 0x04, 0x02, 0x52, 0x0C}, //  63 ?
     {0x00, 0x34, 0x54, 0x64, 0x38}, //  64 @
     {0x00, 0x7C, 0x0A, 0x0A, 0x7C}, //  65 A
     {0x00, 0x7E, 0x4A, 0x4A, 0x34}, //  66 B
     {0x00, 0x3C, 0x42, 0x42, 0x24}, //  67 C
     {0x00, 0x7E, 0x42, 0x42, 0x3C}, //  68 D
     {0x00, 0x3E, 0x4A, 0x4A, 0x42}, //  69 E
     {0x00, 0x7E, 0x0A, 0x0A, 0x02}, //  70 F
     {0x00, 0x3C, 0x42, 0x52, 0x32}, //  71 G
     {0x00, 0x7E, 0x08, 0x08, 0x7E}, //  72 H
     {0x00, 0x00, 0x00, 0x7E, 0x00}, //  73 I
     {0x00, 0x20, 0x40, 0x42, 0x3E}, //  74 J
     {0x00, 0x7E, 0x10, 0x28, 0x46}, //  75 K
     {0x00, 0x3E, 0x40, 0x40, 0x40}, //  76 L
     {0x7E, 0x04, 0x08, 0x04, 0x7E}, //  77 M
     {0x00, 0x7E, 0x04, 0x08, 0x7E}, //  78 N
     {0x00, 0x3C, 0x42, 0x42, 0x3C}, //  79 O
     {0x00, 0x7E, 0x0A, 0x0A, 0x04}, //  80 P
     {0x00, 0x3C, 0x42, 0x22, 0x5C}, //  81 Q
     {0x00, 0x7E, 0x12, 0x32, 0x4C}, //  82 R
     {0x00, 0x44, 0x4A, 0x4A, 0x32}, //  83 S
     {0x00, 0x02, 0x7E, 0x02, 0x00}, //  84 T
     {0x00, 0x3E, 0x40, 0x40, 0x3E}, //  85 U
     {0x00, 0x3E, 0x40, 0x20, 0x1E}, //  86 V
     {0x1E, 0x60, 0x18, 0x60, 0x1E}, //  87 W
     {0x00, 0x76, 0x08, 0x08, 0x76}, //  88 X
     {0x00, 0x46, 0x48, 0x48, 0x3E}, //  89 Y
     {0x00, 0x62, 0x52, 0x4A, 0x46}, //  90 Z
     {0x00, 0x7E, 0x42, 0x00, 0x00}, //  91 [
     {0x00, 0x06, 0x18, 0x60, 0x00}, //  92 \
     {0x00, 0x42, 0x7E, 0x00, 0x00}, //  93 ]
     {0x00, 0x04, 0x02, 0x04, 0x00}, //  94 ^
     {0x00, 0x80, 0x80, 0x80, 0x80}, //  95 _
     {0x00, 0x00, 0x01, 0x02, 0x00}, //  96 `
     {0x00, 0x30, 0x48, 0x28, 0x78}, //  97 a
     {0x00, 0x7E, 0x50, 0x48, 0x30}, //  98 b
     {0x00, 0x30, 0x48, 0x50, 0x00}, //  99 c
     {0x00, 0x30, 0x48, 0x50, 0x7E}, // 100 d
     {0x00, 0x30, 0x68, 0x58, 0x00}, // 101 e
     {0x00, 0x00, 0x7C, 0x0A, 0x00}, // 102 f
     {0x00, 0x18, 0xA4, 0xA8, 0x7C}, // 103 g
     {0x00, 0x7E, 0x10, 0x08, 0x70}, // 104 h
     {0x00, 0x00, 0x74, 0x00, 0x00}, // 105 i
     {0x00, 0x80, 0x88, 0x7A, 0x00}, // 106 j
     {0x00, 0x7E, 0x10, 0x28, 0x40}, // 107 k
     {0x00, 0x00, 0x3E, 0x40, 0x00}, // 108 l
     {0x78, 0x08, 0x70, 0x08, 0x70}, // 109 m
     {0x00, 0x78, 0x10, 0x08, 0x70}, // 110 n
     {0x00, 0x30, 0x48, 0x48, 0x30}, // 111 o
     {0x00, 0xFC, 0x28, 0x24, 0x18}, // 112 p
     {0x00, 0x18, 0x24, 0x28, 0xFC}, // 113 q
     {0x00, 0x78, 0x10, 0x08, 0x10}, // 114 r
     {0x00, 0x4C, 0x54, 0x64, 0x00}, // 115 s
     {0x00, 0x00, 0x3C, 0x48, 0x00}, // 116 t
     {0x00, 0x38, 0x40, 0x20, 0x78}, // 117 u
     {0x00, 0x38, 0x40, 0x20, 0x18}, // 118 v
     {0x38, 0x40, 0x30, 0x40, 0x38}, // 119 w
     {0x00, 0x68, 0x10, 0x68, 0x00}, // 120 x
     {0x00, 0x1C, 0xA0, 0x90, 0x7C}, // 121 y
     {0x00, 0x64, 0x54, 0x4C, 0x00}, // 122 z
     {0x00, 0x08, 0x36, 0x41, 0x00}, // 123 {
     {0x00, 0x00, 0x7F, 0x00, 0x00}, // 124 |
     {0x00, 0x41, 0x36, 0x08, 0x00}, // 125 }
     {0x00, 0x08, 0x04, 0x08, 0x04}, // 126 ~
     {0x00, 0x00, 0x00, 0x00, 0x00}, // 127 DEL
     {0x00, 0x10, 0x38, 0x54, 0x44}, // 128 ?
     {0x00, 0x00, 0xA0, 0x60, 0x00}, // 129 ,
     {0x00, 0x00, 0xA0, 0x60, 0x00}, // 130 ?
     {0x20, 0x48, 0x3E, 0x09, 0x02}, // 131 ?
     {0xA0, 0x60, 0x00, 0xA0, 0x60}, // 132 ?
     {0x40, 0x00, 0x40, 0x00, 0x40}, // 133 ?
     {0x00, 0x04, 0x3E, 0x04, 0x00}, // 134 ?
     {0x00, 0x14, 0x3E, 0x14, 0x00}, // 135 ?
     {0x00, 0x04, 0x02, 0x04, 0x00}, // 136 ?
     {0x62, 0xB5, 0x4A, 0xA4, 0x42}, // 137 ?
     {0x00, 0x49, 0x56, 0x55, 0x24}, // 138 ?
     {0x00, 0x10, 0x28, 0x44, 0x00}, // 139 ?
     {0x38, 0x44, 0x3C, 0x54, 0x44}, // 140 ?
     {0x00, 0x00, 0x00, 0x00, 0x00}, // 141 RI
     {0x00, 0x65, 0x56, 0x55, 0x4C}, // 142 ?
     {0x00, 0x00, 0x00, 0x00, 0x00}, // 143 SS3
     {0x00, 0x00, 0x00, 0x00, 0x00}, // 144 DCS
     {0x00, 0x00, 0x0A, 0x06, 0x00}, // 145 ?
     {0x00, 0x00, 0x06, 0x0A, 0x00}, // 146 ?
     {0x0C, 0x0A, 0x00, 0x0C, 0x0A}, // 147 ?
     {0x0A, 0x06, 0x00, 0x0A, 0x06}, // 148 ?
     {0x00, 0x00, 0x18, 0x18, 0x00}, // 149 ?
     {0x00, 0x00, 0x10, 0x10, 0x00}, // 150 ?
     {0x00, 0x10, 0x10, 0x10, 0x10}, // 151 ?
     {0x00, 0x04, 0x02, 0x04, 0x02}, // 152 ?
     {0x04, 0x1C, 0x1C, 0x08, 0x1C}, // 153 ?
     {0x00, 0x00, 0x59, 0x6A, 0x01}, // 154 ?
..etc..
     {0x00, 0xFE, 0x28, 0x24, 0x18}, // 254 þ
     {0x00, 0x1A, 0xA0, 0xA2, 0x78}, // 255 ÿ
};


I am using standard pgmspace.h library functions to access the data as shown below where START_CHAR  = 1, END_CHAR = 255:

Code: [Select]
unsigned char * copy_char_data(unsigned char c, unsigned char * pos)
{
 unsigned char data = 0;
 if ((c < START_CHAR) || (c >= END_CHAR)) {
   return 0x00;
 }
 return (unsigned char *) memcpy_P(pos, &(font_data[(uint8_t)c - START_CHAR]), 5);
}


I have checked the code for generating the pointer to the start of each character block in the font_data structure and it seems to be generating the correct offset into the array, even for characters beyond '\'.

In my loop () function I have the following code to convert a string to bitmap font data which is held in the planeData array before it is sent to the display driver IC:

Code: [Select]
i =0;
while (str[i] != 0) {
  copy_char_data((unsigned char) str[i], &planeData[k]);
  k = k + 5;
  i++;
}


This all works for characters less than or equal to '\' but not for characters beyond that, they're all off set by one.

Anyone spot any obvious problem or experience anything similar and know what might be going on?

Is there an issue addressing large arrays in PROGMEM?

Thanks!

mikalhart

#1
Sep 24, 2008, 08:32 am Last Edit: Sep 24, 2008, 08:38 am by mikalhart Reason: 1
:)

Easy fix! The problem is that in C, the trailing \ is a line continuation character.  So the line

     {0x00, 0x42, 0x7E, 0x00, 0x00}, //  93 ]

is considered to be a continuation of the comment at the end of the previous line and therefore ignored.  To demonstrate the veracity of this analysis, run the following simple program and see that it prints 1, 2, 3, and 5, but not 4.

Quote
int arr[] =  {
1, // 1
2, // 2
3, // \
4, // 4
5, // 5
};

void setup()
{
 Serial.begin(9600);
 for (int i=0; i<sizeof(arr) / sizeof(int); ++i)
   Serial.println(arr);
}

void loop(){}


Mikal

letaage

I can't believe that was the problem....

I removed the '\' character from the comment and it now works properly.

Thanks!  You don't know how much time I've wasted trying to fix this!

westfw

Quote
Easy fix! The problem is that in C, the trailing \ is a line continuation character.

This must have happened to you before; that's the sort of thing you can stare at for hours and not see...

(It wouldn't happen with /* C-style comments */ )

mikalhart

Quote
This must have happened to you before; --westw


The catalog of my past mistakes is indeed quite hefty. :)

Mikal

Go Up