Moving Sprites to ProgMem

Jim M
  • Jim M

    Jim M - 2013-03-18

    I've downloaded your Serial GLCD code for use in another project driving the SparkFun LCD using a Mega324P. I'm using a 644P for development.
    Instead of using the Backpack AND another chip to run my reflow oven I figured I get a chip with more pins and have it do everything. I've adapted the code to be driven internally and not via UART data. Changed the pin outs, etc.
    Everything works great, text and graphics display properly.
    However, I want to use more sprites and would like to load them to Program space instead of RAM.
    I've tried using the PROGMEM call as used with the font, but get casting warning.

    warning: passing argument 6 of 'bitblt' makes pointer from integer without a cast

    Below is the code I'm trying. (I've removed your comments for brevity)

    original-> char sprite={ <values snipped>};
    new code-> static char sprite PROGMEM = { < values snipped>};

    void draw_sprite(char x, char y, char n, char mode)
    uint16_t o;
    original->bitblt(x, y, sprite, sprite, mode, sprite + 2 + o);
    new code->  bitblt(x, y, pgm_read_byte(&sprite), pgm_read_byte(&sprite), mode, pgm_read_byte(&sprite) + 2 + o);

    Your new code is just great. I'm just having a bit of difficulty (no good with pointers). I appreciate any help you (or someone else) could lend.


  • Jennifer Holt

    Jennifer Holt - 2013-03-19

    The problem is that the pgm_read_byte() call reads 1 byte from program memory and returns this value. The BitBlt function expects a pointer to a section of ram that contain all the necessary data in contiguous bytes (an array). This is so BitBlt can just increment its pointer to retrieve the next byte. In your code:

    new code-> bitblt(x, y, pgm_read_byte(&sprite), pgm_read_byte(&sprite), mode, pgm_read_byte(&sprite) + 2 + o);

    you are sending ((the first value stored in the sprite array) + 2 + o) as a pointer, this will cause BitBlt to take data from ram starting at that address, which is not what you want.

    The easy solution is to make a buffer array and read the sprite data from program memory into it, and then call BitBlt with a pointer to this buffer. Look at how the fonts are done. They use this method, ie the font data is stored in program memory, and a single character is read into a ram buffer right before calling BitBlt. The modified draw_sprite function would look something like this:

    void draw_sprite(char x, char y, char n, char mode) {
      uint16_t  o,j;
    char temp_buffer;

    for (j=0;j<SPRITE_SIZE;j++)   //this loop reads SPRITE_SIZE  single bytes from program memory into a ram buffer

    //then call BitBlt using the buffer you just filled with the sprite data
    bitblt(x, y, temp_buffer, temp_buffer, mode, temp_buffer + 2);

    I have not actually tested this code, but I think it should work.

    The other way would be to write a special bitblt that took its data from program memory. This would be a pain, and since you have lots of memory on your micro the extra buffer (which only has to be as big as a single sprite) shouldn't be a problem.

    Good luck with your project.

  • Jim M

    Jim M - 2013-03-19

    Wow. Thanks, Jenn. I under stand what you mean by passing the buffer not just a pointer to a single buffer location.
    I'll give it a go. Appreciate your help.

  • Jim M

    Jim M - 2013-03-19

    I just tried it out. Worked great.
    But I had an issue adding more sprites to the array until I realized that with more than one sprite, the preceding sprite has to be padded out to the max number of bytes (34), so that the draw_sprite routine indexes into the array the correct number of bytes (n*SPRITE_SIZE) to get to the first byte of the next sprite. I can live with that. The sprites I'll be using will be used as icons, so 16x16 px is just fine.


Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

No, thanks