2017-10-17 21 views
0

펌웨어의 일부로 그래픽 또는 그래픽을 MCU의 EEPROM에 저장하려고합니다. 공간은 1K는 아니지만 프로그램 공간을 절약 할 수 있습니다. 예를 들어 공간을 절약하기 위해 그래픽의 글리프 (glyph)를 분리 할 수는 있지만 관리가 쉽지 않고 표시하기 위해 더 많은 코드가 필요합니다.EEPROM에 그래픽 저장, 공간 절약을 위해 0x00과 0xFF를 반복하여 그래픽 압축 [해결]

대부분의 흑백 GUI 그래픽은 화면을 완전히 채우지 않으며 빈 공간 또는 반복 픽셀 할당을 포함하지 않습니다. 이미지는 이미 압축되어 있으며, 바이트의 각 비트는 8 픽셀을 나타냅니다.

128x32 픽셀의 작은 디스플레이에 그래픽을 표시합니다. 그것을 표시하고 관련성이없는 부품을 지우고 완벽하게 훌륭하고 효율적으로 작동합니다.

나는이 반복을 필터링하여 약간 압축하는 아이디어를 생각해 냈습니다. 성공한 비트 맵 (아래 참조)은 496 바이트이고, 401 바이트 이하의 메소드로 '압축'됩니다. 단지 1K 저장을 사용할 수있을 때 아무리 소리를하지 않습니다

enter image description here



는 정말 좋은 총 크기가 20 % 감소합니다. 바이트 배열의

예 :

PROGMEM const uint8_t TEP_DISPLAY [] = { /* 496 bytes */ 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 
0x06, 0x00, 0x80, 0x90, 0x00, 0x3E, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x47, 0x0F, 0xFE, 
0x17, 0x01, 0xC0, 0x90, 0x00, 0x30, 0x00, 0x00, 0x03, 0x60, 0x01, 0x80, 0x01, 0x87, 0x10, 0x02, 
0x30, 0x83, 0xE3, 0xFC, 0x00, 0x61, 0xE7, 0x39, 0xB6, 0x6F, 0x0F, 0x00, 0x03, 0x07, 0x36, 0xDA, 
0x7F, 0xF0, 0x83, 0xFC, 0x7C, 0x7D, 0xB3, 0x6D, 0xB6, 0x61, 0x9B, 0x1F, 0x03, 0x87, 0x36, 0xDA, 
0x30, 0x43, 0xE1, 0xF8, 0x00, 0x61, 0xB3, 0x6D, 0xA7, 0xCF, 0xB3, 0x00, 0x01, 0x80, 0x36, 0xDA, 
0x13, 0x81, 0xC0, 0x60, 0x00, 0xC3, 0x66, 0x6D, 0xCC, 0x1B, 0x36, 0x00, 0x01, 0x07, 0x10, 0x02, 
0x03, 0x00, 0x80, 0x60, 0x00, 0xFB, 0x66, 0x39, 0x8C, 0x0F, 0x1E, 0x00, 0x02, 0x07, 0x0F, 0xFE, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA2, 0xD5, 0x54, 
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 
0x00, 0xC0, 0x22, 0x00, 0x08, 0x00, 0x02, 0x20, 0x00, 0x82, 0x48, 0x20, 0x00, 0x08, 0x00, 0x00, 
0x40, 0xC0, 0x01, 0xE0, 0x00, 0x01, 0xC0, 0x1E, 0x00, 0x01, 0x50, 0x00, 0xFE, 0x00, 0x0C, 0x02, 
0x00, 0xC0, 0x20, 0x10, 0x08, 0x07, 0xC2, 0x01, 0x00, 0x80, 0x00, 0x21, 0x01, 0x08, 0x0E, 0x00, 
0x4F, 0xFC, 0x00, 0xFE, 0x00, 0x0F, 0x40, 0x3F, 0xF8, 0x03, 0xF8, 0x03, 0x01, 0x80, 0x0B, 0x02, 
0x1C, 0xC2, 0x21, 0x11, 0x08, 0x1C, 0x42, 0x40, 0x04, 0x84, 0x04, 0x21, 0x11, 0x08, 0x69, 0x80, 
0x59, 0xE2, 0x01, 0x11, 0x00, 0x18, 0x40, 0x55, 0x54, 0x05, 0x54, 0x03, 0x39, 0x80, 0x3B, 0x02, 
0x12, 0xD2, 0x21, 0x11, 0x08, 0x10, 0x42, 0x40, 0x04, 0x84, 0x04, 0x21, 0x7D, 0x08, 0x1E, 0x00, 
0x54, 0xCA, 0x01, 0x83, 0x00, 0x10, 0x40, 0x55, 0x54, 0x05, 0x54, 0x03, 0x11, 0x80, 0x3E, 0x02, 
0x12, 0x12, 0x21, 0x01, 0x08, 0x11, 0xC2, 0x40, 0x04, 0x84, 0x04, 0x21, 0x11, 0x08, 0x6B, 0x00, 
0x51, 0xE2, 0x01, 0x01, 0x00, 0x13, 0xC0, 0x47, 0xC4, 0x04, 0x44, 0x01, 0x11, 0x00, 0x09, 0x82, 
0x10, 0x02, 0x21, 0x01, 0x08, 0x71, 0x82, 0x40, 0x04, 0x84, 0x04, 0x23, 0x01, 0x88, 0x0B, 0x00, 
0x4F, 0xFC, 0x01, 0xFF, 0x00, 0xF0, 0x00, 0x3F, 0xF8, 0x05, 0x54, 0x01, 0x01, 0x00, 0x0E, 0x02, 
0x0F, 0xFC, 0x20, 0xFE, 0x08, 0x60, 0x02, 0x1F, 0xF0, 0x84, 0x04, 0x20, 0xFE, 0x08, 0x0C, 0x00, 
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 
}; 

여전히 하나의 문제는 내가 그 코드의 작은 오류라고 생각하고 생각하는 데에 며칠을 보내고 있기 때문에 나는 (그것을 감지 할 수 없습니다 그것을 좀 더 작게 만드는 방법). 어쩌면 문제를 해결하기 위해 올바른 방향으로 나를 안내 할 수있는 누군가가있을 것입니다.

문제가 라인 반복 같은 많은 0xFF를 동일의 255 개 이상의 반복은, similarties의 할당한다 0x00으로 또는 빈 공간을 반복 할 때 문제가 발생

. 내 코드에서는 바이트 오버플로를 피하기 위해 몇 가지 예방 조치를 취하지 만 실패합니다 (그리고 지금은 이유를 알 수 없습니다). 내가하려고하는 것은 오버플로가있을 때 그것을 기록하고 카운트를 통해 다시 시작하는 것입니다. 나는 그것이 읽기 기능이나 쓰기 기능의 문제라는 것을 알 수 없다.

이 저장 여기

At start address: 
----------------- 
<byte width> 
<byte heigth> 
<uint16 dataSize> 
<data> 
    <if data=0xFF> 
    <0xFF> 
    <repeat count> 
    </if> 
    <if data=0x00> 
    <0x00> 
    <repeat count> 
    </if> 
<else data> 
</data> 

의 레이아웃 내 코드입니다 :

<cut, see answer below> 

어떤 아이디어가?


참고 : 나는 고가의 압축 방법을 사용하지 않으

, 프로그램 공간의 96 %가 이미 사용하고 내 방법이 있지만,와 잘 작동하는 것 같다 약간의 오류와 나는 그 대안적인 압축 방법을 알 필요가있다.그것은 약간의 압축을 이미 가지고 있습니다. 8 비트를 표현하기위한 바이트의 비트는 비트를 약간 내리고 싶습니다 (그러나 바이트 넘침시 오류가있는 것으로 증명되었습니다).


EDIT (18) OKT 2017

내 대답 아래 새로운 코드를 참조하십시오.

+0

나쁜 hairday 얘들 아? -1 왜 당신이 downvote 때 설명합니다. – Codebeat

답변

0

잠을 자고 나면 훨씬 더 나은 결과와 적은 코드로 다시 작성 했으므로 그런 일이 너무 복잡해졌습니다.

나는 인상적인 결과를 얻었고 가장 많이 반복하는 바이트를 선택하여 EEPROM '파일'에 기록함으로써 최상의 '압축'을 찾기위한 시험 방법으로이를 수정하려고 생각합니다.

어쨌든이 코드는 첫 코드와 비교하면 훨씬 뛰어납니다. 어쩌면 다른 코드를 도울 수 있습니다. 그것은 몇 바이트를 저장하는 매우 가벼운 솔루션입니다.

예를 들어 128x32 픽셀의 해상도를 가진 빈 화면이나 전체 채워진 화면은 단지 9 바이트이며 반은 17 바이트입니다. 질문에서 보여준 화면은 405 바이트로 컴파일되고 약 100 바이트가 절약됩니다.


uint8_t TOLEDdisplay::getCacheRawBits(uint16_t iAddress) 
{ 
    if(iAddress < cacheSize) 
    { return displayCache[ iAddress ]; } 

    return 0x00; 
} 

bool TOLEDdisplay::setCacheRawBits(uint16_t iAddress, uint8_t iBitByte) 
{ 
    if(iAddress < cacheSize) 
    { 
    displayCache[ iAddress ]=iBitByte; 
    return true; 
    } 

    return false; 
} 

uint16_t TOLEDdisplay::writeToEeprom(uint16_t iAddress) 
{ 
    if(cacheSize == 0 || width == 0 || height == 0) 
    { return 0; } 

    uint8_t iBits;    // Pixel * 8 = byte 
    uint8_t iFoundBits;   // 'Type' of detected 
    uint16_t iByteSize = 0;  // Total byte size of stream 
    uint8_t iCount = 0;  // Count of repeats found 
    bool  bSame;    // Boolean to evaluate repeats 

    // Write screen bounds, when read it back with readFromEeprom, 
    // these bounds need to match with current screen bounds. 
    EEPROM.write(iAddress++, width); 
    EEPROM.write(iAddress++, height); 

    // Reserve two bytes for stream size 
    uint16_t iSizeAddress = iAddress; 
    iAddress+=2; 

    // Write the cache content to the EEPROM 
    uint16_t i = 0; 
    while(i < cacheSize) 
    { 
    // Get a byte with bits 
    iBits = getCacheRawBits(i); 
    ++i; 

    // Find repeating lines or empty lines 
    if(iBits == 0xFF || iBits == 0x00) 
    { 
     iFoundBits = iBits; // Set found bits to detect changes 
     bSame  = true; // Set to true to able to start loop 
     iCount=1;   // Count this found one 

     // Loop to find duplicates 
     while(bSame && (iCount < 0xFF) && (i < cacheSize)) 
     { 
      iBits = getCacheRawBits(i); // Get next byte with bits 
      bSame = (iBits == iFoundBits); // Determine is repeat, the same 
      iCount+=bSame;     // Increment count when same is found 
      i+=bSame; 
     }  

     // Finally write result to EEPROM 
     EEPROM.write(iAddress++, iFoundBits); // type 
     // Write the amount 
     EEPROM.write(iAddress++, iCount); // count 

     // Goto main loop and find next if any 
    } 
    else { 
      // Write found value normally to EEPROM 
      EEPROM.write(iAddress++, iBits); 
     } 
    } 

    // Final EOF address is one pos back 
    --iAddress; 

    // Calculate stream size 
    iByteSize=iAddress-iSizeAddress; 
    uint8_t* pByteSize = (uint8_t*)&iByteSize; 

    // Write size of stream 
    EEPROM.write(iSizeAddress , *pByteSize++); 
    EEPROM.write(iSizeAddress+1, *pByteSize); 

    // return bytes written including width and height bytes (+2 bytes) 
    return iByteSize+2; 
} 

bool TOLEDdisplay::readFromEeprom(uint16_t iAddress) 
{ 
    uint8_t iBits; 
    uint8_t iRepeats; 
    uint16_t i  = 0; 
    uint8_t* pI  = (uint8_t*)&i; 

    uint8_t iWidth = EEPROM.read(iAddress++); 
    uint8_t iHeight = EEPROM.read(iAddress++); 

    // Read stream size, read two bytes 
    *pI = EEPROM.read(iAddress++); 
    *pI++; 
    *pI = EEPROM.read(iAddress++); 

    // Clear the screen 
    clear(); 

    // If an error (no image on EEPROM address) or screen bounds 
    // doesn't match, skip to continue 
    if(i == 0 || iWidth != width || iHeight != height) 
    { 

    update(true); // Set screen to blank 
    return false; 
    } 

    uint16_t iCacheAddress = 0; 

    while(i--) 
    { 
     // Get a byte with bits 
    iBits = EEPROM.read(iAddress++);  

     // Explode repeats if detected 
    if(iBits == 0xFF || iBits == 0x00) 
    { 
     // read amount of repeats 
     iRepeats = EEPROM.read(iAddress++); 

     // Explode it into cache 
     while(iRepeats--) 
     { setCacheRawBits(iCacheAddress++, iBits); } 
    } 
    else { 
      // Put value normally into cache 
      setCacheRawBits(iCacheAddress++, iBits); 
      } 
    } 

    // Done, update the screen 
    update(true); 

    // Return success 
    return true; 
} 
어쩌면 좀 EEPROM의 boundry 검사를 추가해야하지만 지금은 잘 작동 :


여기 내 갱신 코드입니다.

2

처음으로 루프를 통해 bFFOverflowbZeroOverflow이 초기화되지 않고 액세스됩니다.

그러나 중요한 문제는 255 또는 0xFF 바이트를 기록한 후에 더 많은 것이 있으면 개수를 1로 설정한다는 것입니다. 그러나이 바이트의 255 번째 복사본을 계산 한 후에 오버플로를 감지하므로이 값은 0이어야합니다.

따라서 항상 bFFOverflowbZeroOverflow을 0으로 설정하여 계산합니다.

+0

안녕하세요, 빠른 답변 감사드립니다. 당신은 옳지 않습니다, 조건을 검사하기 전에 불공평이 초기화됩니다. 그리고 나는 그것이 중요 할 때 당신이 옳지 않다고 믿습니다. 오버플로가있을 때 0x00 또는 0xFF 조건 중 하나 일 경우 여전히 하나가 남아 있습니다. 그러나, tommorow ;-) 좀 봐 감사 – Codebeat

+0

그냥 초기화 부분에 부울을 false로 변경 테스트, 어떤 의미가 없습니다. – Codebeat