PROGMEM array of 60k not poss on MEGA128

I'm trying to store a char array of sound sample data, under 60Kb. I get "error, array size is too large. If I split it into two arrays I don't get the error. It has to be one array, I need to step through the array at different step sizes to generate different frequencies. This all works fine with an array of less than 32K.

Can anyone help me please? :-/

Some simple modulo arithmetic should cope with the two (or more) smaller arrays.

I tried multidimensional, still got the error if the total memory size exceeded 32K. That would have been an easy solution for me. I'm not sure how to proceed from here if there is in fact a 32k limit to array size using PROGMEM. Perhaps I need an array of pointers? In that case I need to learn a lot more. I have to access the data fast enough to produce 6 different frequencies simultaneously inside an interupt service. Any solution has to be very brief, any guidance appreciated.

Thanks :slight_smile:

While others may be able to provide guidance based on what you've posted. In my case, without a Sketch or more details, I cannot.

unsigned char E0[] PROGMEM = {124, 127, 132, 127, 123, 125, 119, 114, 115, 83, 55, 118, 176,... about 60,000 values };
gives error, less than 32,000 values in the array works fine.

So if I divide this into say 256 x 256 arrays and use an unsigned int to access, high byte and low byte, how do I apply this in terms of PROGMEM?

This works fine for up to 32k of data
comb =(pgm_read_byte(&(E0[tempindex])));
if (waveindex < lastsample){waveindex+=inc;}

thanks for any help

If you have two arrays, each less that 30K, and the index is greater than 30K, read from the 2nd array, using index-30000.

Wow, that sounds so simple, and logical. I've just downloaded "Flashlibrary" and that does not seem to mind arrays bigger than 32k. Just going to check if there is going to be a time overhead problem inside the ISR using "Flash library". I'll try your solution next.

Thanks very much! ::slight_smile:

I wrote too soon, after adjusting the rest of the code to accomodate "Flash" library I'm getting the array too large error again.

Paul, I'll try your solution in the morning, close to midnight here and I started on this at 9am :wink:

Another failure :cry: A negative value for the array index did not work, just white noise from output (sound data is plucked guitar string) Then an inspiration, PROGMEM the data in two arrays, use the the first array as "base" and index through it and into the second array.

Failure :cry: :cry: The first 2 seconds sound fine then white noise for the second half. I need to see where the data is being put in memory, how do I do that? I'm using standard Arduino environment in Windows. Also Processing for helper data organising routines (write the data header file)

Thanks for any help :stuck_out_tongue:

A negative index will always fail, irrespective of the ssize of the array UNLESS the array is accessed via a pointer offset from the zoreth index (handy for lookup tables involving negative numbers)

Maybe now is a good time to post code?

unsigned int lastsamp = 60000;
volatile unsigned long waveindex0;
volatile int inc0;
volatile unsigned int comb;
volatile unsigned int tempindex;

const unsigned char E00[] PROGMEM = {124, 127, 132, 127,...30k of samples
const unsigned char E0[] PROGMEM = {124, 127, 132, 127,...30k of samples
error if more than 32k in one array.

//Timer 4 on port H
TCCR4A = B10101010;//
TCCR4B = B00011001;//
TIMSK4 = B00100000;//flag mask, enable TOP int on top
ICR4 = 1000;//set top value, should be 1000 for 16KHz sample rate

ISR(TIMER4_CAPT_vect) {// ready for next sample
tempindex = waveindex0>>8;//lower 8 bits only used for fractional stepping through audio data

comb =(pgm_read_byte_far(&(E00[tempindex])));//tried with and without _far, gets lost at 32k(random noise)

if (tempindex < lastsamp){waveindex0+=inc0;}//inc waveindex and load next sample until it has reached the end of the second array
OCR4A=comb;//PWM

Thanks for any help

Caveat: I don't have a Mega:

#include <avr/pgmspace.h>
// appropriate declarations of  SEGMENT_SIZE
// and N_SEGMENTS here

prog_char sample0 [SEGMENT_SIZE] PROGMEM = {   };
prog_char sample1 [SEGMENT_SIZE] PROGMEM = {   };
prog_char sample2 [SEGMENT_SIZE] PROGMEM = {   };
prog_char sample3 [SEGMENT_SIZE] PROGMEM = {   };

unsigned long iliffe [N_SEGMENTS] = {(unsigned long) sample0,
                                     (unsigned long) sample1,
                                     (unsigned long) sample2,
                                     (unsigned long) sample3,
                                   };

char getSample (unsigned long index)
{
  int iliffeIndex = index / SEGMENT_SIZE;
  int arrayIndex  = index % SEGMENT_SIZE;
  char val;
  (void)memcpy_P ((void*)&val,(PGM_VOID_P) (iliffe [iliffeIndex]  + arrayIndex), 1);
  return val;
}

(and I'm sure the program memory access could be simplified)

Thanks very much AWOL :wink: Some of the terms I'm unfamiliar with but I can just about get the gist of it. I'll look up prog_char and that memcpy stuff. The syntax is hard going for a non programmer.

My concern now is I need to use your code six times in the ISR, and all the time the clock is ticking! Well, I'd just about reconciled myself to being happy with max 2 second sample time so nothing to lose and everything (about 6 sec) to again.

Will let you know how it works out ::slight_smile:

OK, an Iliffe vector is simply a table of pointers to other arrays, typically vectors.
It is normally used if the shape of the intended array is not rectangular, say a triangle or a circle, where the Iliffe vector entries point to adjacent chords of the circle.

Here, however, the array is a simple vector, but not compilable.
So, we break it into a number of smaller vectors, each with their staring addresses held in the Iliffe vector.

Note that with an Iliffe vector, the arrays segments do not have to be consecutive in memory, and the segments do not have to be the same length, though if they are not, you are advised to have a second vector giving the segment lengths.

[edit] I forgot: I compiled my test on a processor that doesn't have "pgm_read_byte_far", so :
return pgm_read_byte_far(iliffe [iliffeIndex] + arrayIndex);
should do the trick on a Mega.[/edit]

AWOL, I have a working synthetic guitar that sounds very nice even before filtering!

I studied your code until fairly comfortable with it and started to implement. I looked up prog_char and realised I should have been using prog_uchar and not unsigned char for PROGMEM. On whim I changed this in my code and recompiled, immiediatly noticing for the first time the program size was now over 65k! I had been wondering why it never got beyond 35K...

I'm now wondering whether you can in fact have arrays bigger than 32K. Almost irrelevent now but I will try again with a single array.

Thanks again, I would not have found this without your code to look at and I'm sure the knowledge you've imparted will be very useful to me.

A very happy bunny ;D ;D ;D

thanks for the edit, I tried with _far earlier, it got very flaky with the overhead. It's working fine now without the _far but I'm sure I'm very close to the limit, at least until there is a faster clock speed available.

::slight_smile:

Unless you're doing arithmetic on the retrieved values, I can't really see why there should be a difference between "prog_char" and "prog_uchar".

I think the "near" macros use a signed 16 bit offset, so an offset of > 32767 is going to be tricky.