I'm writing a function to store the contents of VRAM into a 24-bit .bmp, but I have no idea why it's not working. Previously I was using the 16-bit RGB 565 bitmap header, but that produced really strange colors.

Here's the code:

Code:
#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
#define READ 0
#define READ_SHARE 1
#define WRITE 2
#define READWRITE 3
#define READWRITE_SHARE 4

#define RETURN_SUCCESS 0
#define RETURN_ERROR -1

#define LCD_WIDTH 384
#define LCD_HEIGHT 216

#define file_size sizeof(bmpheader)+(LCD_WIDTH*LCD_HEIGHT*3)

unsigned short filebuffer[] = {'\\','\\','f','l','s','0','\\','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'}; 
unsigned char bmpheader[] =
   {0x42, 0x4D, 0x36, 0xCC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
int TakeScreenshot(char* filename) //Copies the contents of VRAM to a 24-bit .bmp file in storage memory
{
   int fh = 0;   
   Bfile_StrToName_ncpy(filebuffer+(7), filename, strlen(filename)); //copy the filename to the filebuffer after "\\fls0\"
   Bfile_DeleteEntry(filebuffer, CREATEMODE_FILE, 0);
   color_t* VRAM = (color_t*)0xA8000000;
   int size = file_size;
   if (0 > (fh = Bfile_OpenFile_OS(filebuffer,READWRITE))) {
        if (Bfile_CreateEntry_OS(filebuffer, CREATEMODE_FILE, &size) < 0)
         return RETURN_ERROR;
   }
   if (fh >= 0)
        Bfile_CloseFile_OS(fh);
   if (0 <= (fh = Bfile_OpenFile_OS(filebuffer,READWRITE))) {
      Bfile_WriteFile_OS(fh, bmpheader, sizeof(bmpheader));
      void* scratchSpace = malloc(LCD_WIDTH*3);
      for (int x = LCD_HEIGHT-1; x >= 0; x--) //bmp files are upside down
      {
         //memcpy(scratchSpace, VRAM+(LCD_WIDTH*x), LCD_WIDTH*2); <-- produces weird colors in 16 bit mode
         
         for (int y = 0; y < LCD_WIDTH; y++) // http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888
         {
            unsigned short color = (unsigned short*)(VRAM+(LCD_WIDTH*x+y));
            unsigned char red = (char)((color & 0xf800) >> 11);
            unsigned char green = (char)((color & 0x07e0) >> 5);
            unsigned char blue = (char)(color & 0x001f);
            *((char*)scratchSpace+3*y) = ( red * 527 + 23 ) >> 6;
            *((char*)scratchSpace+3*y+1) = ( green * 259 + 33 ) >> 6;
            *((char*)scratchSpace+3*y+2) = ( blue * 527 + 23 ) >> 6;
         }
         Bfile_WriteFile_OS(fh, scratchSpace, LCD_WIDTH*3); //write chunk to file
      }   
      free(scratchSpace);
      Bfile_CloseFile_OS(fh);
   }   
   
   return RETURN_SUCCESS;
}


Edit: Here's the complete, functioning code with Tari's assembly code.

Code:
#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
#define READ 0
#define READ_SHARE 1
#define WRITE 2
#define READWRITE 3
#define READWRITE_SHARE 4
#define RETURN_SUCCESS 0
#define RETURN_ERROR -1
#define LCD_WIDTH 384
#define LCD_HEIGHT 216
#define file_size sizeof(bmpheader)+(LCD_WIDTH*LCD_HEIGHT*2)

unsigned short filebuffer[] = {'\\','\\','f','l','s','0','\\','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'}; 
unsigned char bmpheader[] =
   {0x42, 0x4D, 0x46, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

int TakeScreenshot(char* filename) //Copies the contents of VRAM to a 16-bit .bmp file in storage memory
{
   int fh = 0;   
   Bfile_StrToName_ncpy(filebuffer+(7), filename, strlen(filename)); //copy the filename to the filebuffer after "\\fls0\"
   Bfile_DeleteEntry(filebuffer, CREATEMODE_FILE, 0);
   color_t* VRAM = (color_t*)0xA8000000;
   int size = file_size;
   if (Bfile_CreateEntry_OS(filebuffer, CREATEMODE_FILE, &size) < 0)
      return RETURN_ERROR;
   if (0 <= (fh = Bfile_OpenFile_OS(filebuffer,READWRITE))) {
      Bfile_WriteFile_OS(fh, bmpheader, sizeof(bmpheader));
      void* scratchSpace = malloc(LCD_WIDTH*2);
      for (int x = LCD_HEIGHT-1; x >= 0; x--) //bmp files are upside down
      {
         memcpy_littleendian(scratchSpace, VRAM+(LCD_WIDTH*x), LCD_WIDTH*2);// <-- produces weird colors in 16 bit mode
         Bfile_WriteFile_OS(fh, scratchSpace, LCD_WIDTH*2); //write chunk to file         
      }   
      free(scratchSpace);
      Bfile_CloseFile_OS(fh);
   }      
   return RETURN_SUCCESS;
}
void memcpy_littleendian(void* dest, void* source, int length)
{
   /*unsigned char* dst = (unsigned char*)dest;
   unsigned char* src = (unsigned char*)source;   
   for (int x = 0; x < length; x+=2)
   {
      *(dst+x) = *(src+x+1);
      *(dst+x+1) = *(src+x);
   }*/
   unsigned short *s = (unsigned short *)source;
    unsigned short *d = (unsigned short *)dest;
    while (length--) {
        unsigned short c = *s++;
        __asm__("swap.b %0,%0" : "=r"(c) : "0"(c));
        *d++ = c;
    }
}

Remember to check your endianness. The 7305 is big endian whereas your PC is little endian. All values in the BMP format must be in little endian format. To make that work, make your own memcpy to flip the endianness when it copies and your 16 bit 56500 bmp should work.

Also, the order of Bfile calls is a bit :-\. You should do Bfile_StrToName -> Bfile_DeleteEntry -> Bfile_CreateEntry -> Bfile_OpenFile.

<edit>

To 'swap' endianness, you can use the SWAP instruction if you are using asm. Otherwise, here is the C equiv. according to Renesas:
Code:
SWAPB(long m, long n)
 /* SWAP.B Rm,Rn */
{
unsigned long temp0,temp1;
temp0 = R[m] & 0xFFFF0000;
temp1 = (R[m] & 0x000000FF) << 8;
R[n] = (R[m] & 0x0000FF00) >> 8;
R[n] = R[n] | temp1 | temp0;
PC += 2;
}
Thanks, I got it working.

Code:
#define CREATEMODE_FILE 1
#define CREATEMODE_FOLDER 5
#define READ 0
#define READ_SHARE 1
#define WRITE 2
#define READWRITE 3
#define READWRITE_SHARE 4
#define RETURN_SUCCESS 0
#define RETURN_ERROR -1
#define LCD_WIDTH 384
#define LCD_HEIGHT 216
#define file_size sizeof(bmpheader)+(LCD_WIDTH*LCD_HEIGHT*2)
unsigned short filebuffer[] = {'\\','\\','f','l','s','0','\\','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'}; 
unsigned char bmpheader[] =
   {0x42, 0x4D, 0x46, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
int TakeScreenshot(char* filename) //Copies the contents of VRAM to a 16-bit .bmp file in storage memory
{
   int fh = 0;   
   Bfile_StrToName_ncpy(filebuffer+(7), filename, strlen(filename)); //copy the filename to the filebuffer after "\\fls0\"
   Bfile_DeleteEntry(filebuffer, CREATEMODE_FILE, 0);
   color_t* VRAM = (color_t*)0xA8000000;
   int size = file_size;
   if (Bfile_CreateEntry_OS(filebuffer, CREATEMODE_FILE, &size) < 0)
      return RETURN_ERROR;
   if (0 <= (fh = Bfile_OpenFile_OS(filebuffer,READWRITE))) {
      Bfile_WriteFile_OS(fh, bmpheader, sizeof(bmpheader));
      void* scratchSpace = malloc(LCD_WIDTH*2);
      for (int x = LCD_HEIGHT-1; x >= 0; x--) //bmp files are upside down
      {
         memcpy_littleendian(scratchSpace, VRAM+(LCD_WIDTH*x), LCD_WIDTH*2);//
         Bfile_WriteFile_OS(fh, scratchSpace, LCD_WIDTH*2); //write chunk to file         
      }   
      free(scratchSpace);
      Bfile_CloseFile_OS(fh);
   }      
   return RETURN_SUCCESS;
}
void memcpy_littleendian(void* dest, void* source, int length)
{
   unsigned char* dst = (unsigned char*)dest;
   unsigned char* src = (unsigned char*)source;   
   for (int x = 0; x < length; x+=2)
   {
      *(dst+x) = *(src+x+1);
      *(dst+x+1) = *(src+x);
   }
}


Edit: Oops, I didn't see your edit. I'll try to incorporate that asm code into my memcpy function.
souvik1997 wrote:
Edit: Oops, I didn't see your edit. I'll try to incorporate that asm code into my memcpy function.
Simple variant:
Code:
void *memcpy_to_le(void *dst, const void *src, size_t n) {
    unsigned short *s = (unsigned short *)src;
    unsigned short *d = (unsigned short *)dst;
    while (n--) {
        unsigned short c = *s++;
        asm("swap.b %0,%0" : "=r"(c) : "0"(r));
        *d++ = c;
    }
}
The interesting bit is really just the asm() directive.
It's entirely possible that GCC will optimize the shift+mask sequence that you'd use for endianness-flipping without machine support into the processor's primitive. I haven't tested it, but it's worth trying.
Very nice that you got it working Very Happy
Tari wrote:
The interesting bit is really just the asm() directive.
It's entirely possible that GCC will optimize the shift+mask sequence that you'd use for endianness-flipping without machine support into the processor's primitive. I haven't tested it, but it's worth trying.
I noticed these builtins while browsing the GCC documentation, which are probably slightly easier variants of what I said.
Code:
int16_t __builtin_bswap16 (int16_t x)
int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)
These flip the endianness of 16, 32 and 64-bit arguments, respectively.
Ah, I also came across those. They produce the SWAP op code directly, so use them when possible
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement