The Bubbleworks / NanoBit

Dependents:   TheBubbleWorks_MicroBorg

Fork of NanoBit by Wayne Keenan

NanoBitDisplay.cpp

Committer:
waynek
Date:
2016-02-10
Revision:
1:7a9d736530c8
Parent:
BBL_MicroBit_Display.cpp@ 0:b34dc22c2bdd
Child:
2:b45f392b18eb

File content as of revision 1:7a9d736530c8:

#include <new>
#include "nrf_gpio.h"
#include "mbed.h"
#include "NanoBitDisplay.h"

#define MY_DBG_ENABLED 1
#include "MyDebug.h"


const uint8_t panicFace[MICROBIT_DISPLAY_COLUMN_COUNT] = {0x1B, 0x1B,0x0,0x0E,0x11};

const uint8_t heart[]={ 
0, 1, 0, 1, 0, 
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 
0, 0, 1, 0, 0}; // a cute heart

const MatrixPoint MicroBitDisplay::matrixMap[MICROBIT_DISPLAY_COLUMN_COUNT][MICROBIT_DISPLAY_ROW_COUNT] = 
{   
    {MatrixPoint(0,0),MatrixPoint(4,2),MatrixPoint(2,4)},
    {MatrixPoint(2,0),MatrixPoint(0,2),MatrixPoint(4,4)},
    {MatrixPoint(4,0),MatrixPoint(2,2),MatrixPoint(0,4)},  
    {MatrixPoint(4,3),MatrixPoint(1,0),MatrixPoint(0,1)},
    {MatrixPoint(3,3),MatrixPoint(3,0),MatrixPoint(1,1)},
    {MatrixPoint(2,3),MatrixPoint(3,4),MatrixPoint(2,1)},
    {MatrixPoint(1,3),MatrixPoint(1,4),MatrixPoint(3,1)},
    {MatrixPoint(0,3),MatrixPoint(NO_CONN,NO_CONN),MatrixPoint(4,1)},
    {MatrixPoint(1,2),MatrixPoint(NO_CONN,NO_CONN),MatrixPoint(3,2)}
};
    
/**
  * Constructor.
  * Create a representation of a display of a given size.
  * The display is initially blank.
  *
  * @param x the width of the display in pixels.
  * @param y the height of the display in pixels.
  * 
  * Example:
  * @code 
  * MicroBitDisplay display(MICROBIT_ID_DISPLAY, 5, 5),
  * @endcode
  */
MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) {
    //set pins as output
    nrf_gpio_range_cfg_output(MICROBIT_DISPLAY_COLUMN_START,MICROBIT_DISPLAY_COLUMN_START + MICROBIT_DISPLAY_COLUMN_COUNT + MICROBIT_DISPLAY_ROW_COUNT);
    
    this->width = x;
    this->height = y;
    this->strobeRow = 0;
    this->strobeBitMsk = 0x20;
//    this->timingCount = 0;
    
    this->setBrightness(MICROBIT_DEFAULT_BRIGHTNESS);
    uint8_t defaultBitmap[MICROBIT_DISPLAY_COLUMN_COUNT]= { 
    0b101010,
    0b101010,
    0b101010,
    0b101010,
    0b101010
    };
    
    //memcpy(bitmap, panicFace, sizeof(bitmap));
    memcpy(bitmap, heart, sizeof(bitmap));
    systemTicker.attach(this, &MicroBitDisplay::systemTick, MICROBIT_DISPLAY_REFRESH_PERIOD);     

}

/**
  * Internal frame update method, used to strobe the display.
  *
  * TODO: Write a more efficient, complementary variation of this method for the case where 
  * MICROBIT_DISPLAY_ROW_COUNT > MICROBIT_DISPLAY_COLUMN_COUNT.
  */   
void MicroBitDisplay::systemTick()
{           
    // Move on to the next row. 
    strobeBitMsk <<= 1;
    strobeRow++;
        
    //reset the row counts and bit mask when we have hit the max.
    if(strobeRow >= MICROBIT_DISPLAY_ROW_COUNT){
        strobeRow = 0;
        strobeBitMsk = 0x20;   
    }
      
    render();
}

void MicroBitDisplay::renderFinish()
{
    //kept inline to reduce overhead
    //clear the old bit pattern for this row.
    //clear port 0 4-7 and retain lower 4 bits
    nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F); 
    
    // clear port 1 8-12 for the current row
    nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | 0x1F); 
}

void MicroBitDisplay::render()
{   
    if(brightness == 0)
        return;

    int coldata = 0;
    
    // Calculate the bitpattern to write.
    for (int i = 0; i<MICROBIT_DISPLAY_COLUMN_COUNT; i++)
    {
        //MY_DBG_PRINTF("%d,%d,", i, strobeRow);
        int x = matrixMap[i][strobeRow].x;
        int y = matrixMap[i][strobeRow].y;        
        //MY_DBG_PRINTF("%d,%d => bitmap[%d]\n", x,y, y*(width*2)+x);
        
        if(bitmap[y*(width)+x]) {

            coldata |= (1 << i);
        }
    }
                    
    //write the new bit pattern
    //set port 0 4-7 and retain lower 4 bits
    nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, ~coldata<<4 & 0xF0 | nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F); 
    
    //set port 1 8-12 for the current row
    nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); 

    //timer does not have enough resolution for brightness of 1. 23.53 us
    if(brightness != MICROBIT_DISPLAY_MAX_BRIGHTNESS && brightness > MICROBIT_DISPLAY_MIN_BRIGHTNESS)
        renderTimer.attach(this, &MicroBitDisplay::renderFinish, (((float)brightness) / ((float)MICROBIT_DISPLAY_MAX_BRIGHTNESS)) * (float)MICROBIT_DISPLAY_REFRESH_PERIOD);
    
    //this will take around 23us to execute
    if(brightness <= MICROBIT_DISPLAY_MIN_BRIGHTNESS)
        renderFinish();
}


/**
  * Enables the display, should only be called if the display is disabled.
  *
  * Example:
  * @code 
  * uBit.display.enable(); //reenables the display mechanics
  * @endcode
  */
void MicroBitDisplay::enable()
{
    setBrightness(brightness);
}
    
/**
  * Disables the display, should only be called if the display is enabled.
  * Display must be disabled to avoid MUXing of edge connector pins.
  *
  * Example:
  * @code 
  * uBit.display.disable(); //disables the display
  * @endcode
  */
void MicroBitDisplay::disable()
{
}

/**
  * Clears the current image on the display.
  * Simplifies the process, you can also use uBit.display.image.clear
  *
  * Example:
  * @code 
  * uBit.display.clear(); //clears the display
  * @endcode
  */ 
void MicroBitDisplay::clear()
{
    memset(bitmap, 0, sizeof(bitmap));
}


/**
  * Sets the display brightness to the specified level.
  * @param b The brightness to set the brightness to, in the range 0..255.
  * 
  * Example:
  * @code 
  * uBit.display.setBrightness(255); //max brightness
  * @endcode
  */  
void MicroBitDisplay::setBrightness(int b)
{   
    //sanitise the brightness level
    if(b < 0)
        b = 0;
    
    if (b > 255)
        b = 255;

    this->brightness = b;
}