Renesas GR-Peach LCD Interface

Dependencies:   EthernetInterface HTTPD PubNub SDFileSystem mbed-rtos mbed picojson

Renesas GR-Peach LCD Interface

lcd_main.cpp

Committer:
nikhilchaturtvedi
Date:
2015-10-23
Revision:
0:0b32d3eaabfe

File content as of revision 0:0b32d3eaabfe:

#include "gen_helper.h"
#include "math.h"


/* An SPI Master for interfacing and handling an LCD Slave with GR-Peach */


/* Variables for holding previously drawn co-ordinate values */
int x_left = 0; //holder for the last updated x co-ordinate value for the left side
int y_left = 0; //holder for the last updated y co-ordinate value for the left side
int x_right = 0; //holder for the last updated x co-ordinate value for the right side
int y_right = 0; //holder for the last updated y co-ordinate value for the right side

//The number of the levels for the tree.
//This is declared here for ease of change in any function and reset it to
//the original value after use.
int number_levels = 0;

gen_helper::gen_helper(PinName MOSI, PinName MISO, PinName SCK, PinName CS, PinName Reset, PinName RS, PinName _USBTX, PinName _USBRX, PwmOut _pwm) : 
            lcd(MOSI, MISO, SCK), ssel(CS), reset(Reset), rs(RS), console(_USBTX, _USBRX), pwm(_pwm)
{
    _height = SCREEN_HEIGHT;
    _width = SCREEN_WIDTH;
}


/* Init console by setting the baud rate */

void gen_helper::init_console()
{
    //init serial over USB here
    console.baud(115200);
    console.printf("Console init done\n");
}

/**
 * Draws a line by a factor of lambda value
 *(x0,y0) are initial co-ordinates and (x1,y1) are the end co-ordinates

 * x0 - starting x co-ordinate value
 * y0 - starting y co-ordinate value
 * x1 - end x co-ordinate value
 * y1 - end y co-ordinate value
 * lambda - the factor that decides the length of the resulting line segment
 */
void gen_helper::massaged_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, float lambda, uint16_t colour, uint16_t *X, uint16_t *Y)
{
    *X = (uint16_t)(x0 + (lambda * (x1 - x0)));
    *Y = (uint16_t)(y0 + (lambda * (y1 - y0)));
}


/**
 * rotate (x2,y2) around (x1,y1) by alpha degrees
 * combines rotation and translation also.

 * x1 - starting x co-ordinate
 * y1 - starting y co-ordinate
 * x2 - end x co-ordinate
 * y2 - end y co-ordinate
 * alpha - the degree of rotation required
 */
void gen_helper::rotate_line(float x1, float y1, float x2, float y2, uint16_t alpha, float *X, float *Y)
{
    float radian = (3.1415 * alpha / 180);
    *X = (x2 - x1) * cosf(radian) - (y2 - y1) * sinf(radian) + x1;
    *Y = (y2 - y1) * cosf(radian) + (x2 - x1) * sinf(radian) + y1;
}


/**
 * Draw a line with the init and end co-ordinates
 * (x0, y0) - start co-ordinates
 * (x1, y1) - end co-ordinates
 * color - color of the line
 * Based on the ST7735 source
*/
void gen_helper::drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1,uint16_t color)
{
    int16_t x, y;
    float slope;
    
    //check for slope conditions
    if( (x0 != x1) && (y0 != y1) ) 
    {
        slope = (y1 - y0) / (x1 - x0);
        
        if (abs(slope) < 1) 
        {
            for(x = x0; x < x1 + 1; x++) 
            {
                y = (x - x0) * slope + y0;
                draw_pixel(x, (y + 0.5), color);
            }
        } 
        else 
        {
            for(y = y0; y < y1 + 1; y++) 
            {
                x = (y - y0) / slope + x0;
                draw_pixel((x + 0.5), y, color);
            }
        }
    }
}

/**
 * A helper function which is flexible enough to be
 * given any pattern to be drawn on the LCD
 * initial values are (20,0) and (20,20) and the number of levels in 7
 */
void gen_helper::draw_pattern_helper()
{
    int first_x0 = 20;
    int first_y0 = 0;
    int first_x1 = 20;
    int first_y1 = 20;
    //set the number of levels of the tree to 7
    number_levels = 7;

    //Draw the first tree
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);


    //The second tree in the same plane
    int next_tree_index = first_x0 + 30;
    first_x0 = next_tree_index;
    first_x1 = first_x0;

    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Third tree
    next_tree_index += 30;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Fourth tree
    next_tree_index += 30;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Fifth tree which starts at a much higher level than the previous trees
    next_tree_index = 35;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    first_y0+=20;
    first_y1+=20;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Sixth tree that is at the same level as fifth
    next_tree_index = 65;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Seventh tree that is at the same level as sixth
    next_tree_index = 95;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);


    //Eighth tree at the same level as seventh
    next_tree_index = 20;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    first_y0 = 90;
    first_y1 = first_y0 + 20;
    number_levels = 3;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Ninth tree at the same level as eight but with only 3 levels
    next_tree_index = 50;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    first_y0 = 90;
    first_y1 = first_y0 + 20;
    number_levels = 3;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Tenth tree at the same level as ninth but with only 3 levels
    next_tree_index = 80;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    first_y0 = 90;
    first_y1 = first_y0 + 20;
    number_levels = 3;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

    //Eleventh tree at the same level as tenth but with only 3 levels
    next_tree_index = 110;
    first_x0 = next_tree_index;
    first_x1 = first_x0;
    first_y0 = 90;
    first_y1 = first_y0 + 20;
    number_levels = 3;
    draw_custom_pattern(first_x0, first_y0, first_x1, first_y1);

}


/**
 * Draw the forest in any pattern that is desired with
 * given two sets of start and end points
 
 * x0 - starting x co-ordinate value
 * y0 - starting y co-ordinate value
 * x1 - end x co-ordinate value
 * y1 - end y co-ordinate value
 *
 */
void gen_helper::draw_custom_pattern(int x0, int y0, int x1, int y1)
{
    int first_x0 = x0;
    int first_y0 = y0;
    int first_x1 = x1;
    int first_y1 = y1;
    int temp_leftx = 0;
    int temp_lefty = 0;
    int temp_rightx = 0;
    int temp_righty = 0;
    int r_temp_leftx = 0;
    int r_temp_lefty = 0;
    int r_temp_rightx = 0;
    int r_temp_righty = 0;

    //draw the initial trunk of the tree and the next vertical branch that is
    //a shrunken version of the trunk
    drawLine(first_x0, first_y0, first_x1, first_y0+10, BLACK);
    drawLine(first_x0+1, first_y0, first_x1+1, first_y0+10, BLACK);
    draw_pattern(first_x0, first_y0+10, first_x1, first_y1+10);


    //The pattern for drawing the tree and hence the forest.
    //This can be any pattern required.
    temp_leftx = x_left;
    temp_lefty = y_left;
    temp_rightx = x_right;
    temp_righty = y_right;

    r_temp_leftx = x_left;
    r_temp_lefty = y_left;
    r_temp_rightx = x_right;
    r_temp_righty = y_right;


    int i = 0;
    for(i = 0; i < number_levels; i++)
    {
        draw_pattern(r_temp_leftx, r_temp_lefty, r_temp_leftx, r_temp_lefty+10);
        draw_pattern(r_temp_rightx, r_temp_righty, r_temp_rightx, r_temp_righty+10);
        r_temp_leftx = x_left;
        r_temp_lefty = y_left;
        r_temp_rightx = x_right;
        r_temp_righty = y_right;
    }

    i = 0;
    for(i = 0; i < number_levels; i++)
    {
        draw_pattern(temp_rightx, temp_righty, temp_rightx, temp_righty+10);
        draw_pattern(temp_leftx, temp_lefty, temp_leftx, temp_lefty+10);
        temp_leftx = x_left;
        temp_lefty = y_left;
        temp_rightx = x_right;
        temp_righty = y_right;
    }

}


/**
 *
 * x1 - starting x co-ordinate value
 * y1 - starting y co-ordinate value
 * x2 - end x co-ordinate value
 * y2 - end y co-ordinate value
 */
void gen_helper::draw_pattern(int x1, int y1, int x2, int y2)
{

    int first_x0 = x1;
    int first_y0 = y1;
    int first_x1 = x2;
    int first_y1 = y2;
    int alpha = 30;
    int neg_alpha = -30;


    float x0=0, y0=0;

    rotate_line(first_x0, first_y0, first_x1, first_y1, alpha, &x0, &y0);

    drawLine(first_x0, first_y0, (int)x0, (int)y0, GREEN);

    x_right = (int)x0;
    y_right = (int)y0;

    x0 = 0;
    y0 = 0;

    rotate_line(first_x0, first_y0, first_x1, first_y1, neg_alpha, &x0, &y0);
    drawLine(first_x0, first_y0, (int)(x0+3), (int)y0, GREEN);

    x_left = (int)x0+3;
    y_left = (int)y0;


}

/********* SD card helper functions; wrappers over the SD card file system ********/
uint8_t gen_helper::init_disk()
{
    return sd_fs->disk_initialize();
}

/**
* Initialize the SD card
*/
uint8_t gen_helper::init_SD()
{
    sd_fs = new SDFileSystem(P8_5, P8_6, P8_3, P8_4, "sd");
    
    if(sd_fs)
        return (uint8_t)0; //force a casting
    else
        return (uint8_t)-1;
}

/**
* Open a file and return the file descriptor
*/
FILE* gen_helper::open_file(char *path, char *mode)
{
    return fopen(path, mode);
}

uint8_t gen_helper::close_file(FILE *fp)
{
    return fclose(fp);
}

uint8_t gen_helper::make_dir(char *path, uint32_t mode)
{
    return mkdir(path, mode);
}

uint8_t gen_helper::remove_file(char *path)
{
    return remove(path);
}
/****SD card function implementations end****/


/* Initialize the LCD 
* 
*TODO : Check the row select and col select for Renesas GR-PEACH 
*
* Based on the specs from ST7735
*/
void gen_helper::lcd_init()
{
    console.printf("Writing to the lcd \n");
 
    lcd.format(8, 3);
    //lcd.frequency(15000000);
    ssel = 0;
    reset = 1;
    wait_ms(500);
    reset = 0;
    wait_ms(500);
    reset = 1;
    wait_ms(500);
    
    write_spi_command(SW_RESET);                         // SW Reset                       
    wait_ms(150);
    write_spi_command(AWAKE_SLEEPMODE);                         // Out of sleepmode               
    wait_ms(500);
    
    write_spi_command(FRAMERATE_NORMAL);                         // Frame rate in normal mode
    write_spi_data(0x01);                              
    write_spi_data(0x2C);
    write_spi_data(0x2D);
    
    write_spi_command(FRAMERATE_IDLE);                         // Frame rate in idle mode
    write_spi_data(0x01);                              
    write_spi_data(0x2C);
    write_spi_data(0x2D);

    write_spi_command(FRAMERATE_PARTIAL);                         // Frame rate in partial mode
    write_spi_data(0x01);                              
    write_spi_data(0x2C);
    write_spi_data(0x2D);
    write_spi_data(0x01);   // inversion mode settings                              
    write_spi_data(0x2C);
    write_spi_data(0x2D);
    
    write_spi_command(INVERTED_MODE_OFF);   // Inverted mode off
    write_spi_data(0x07);   

    write_spi_command(POWER_CONTROL_1);
    write_spi_data(0xA2); 
    write_spi_data(0x02);  
    write_spi_data(0x84);  
    
    write_spi_command(POWER_CONTROL_2);   // POWER CONTROL 2   
    write_spi_data(0xC5);            
    
    write_spi_command(POWER_CONTROL_3);  // POWER CONTROL 3   
    write_spi_data(0x0A);           
    write_spi_data(0x00);           

    write_spi_command(POWER_CONTROL_4);   // POWER CONTROL 4   
    write_spi_data(0x8A);           
    write_spi_data(0x2A);   
  
    write_spi_command(POWER_CONTROL_5);   // POWER CONTROL 5   
    write_spi_data(0x8A);           
    write_spi_data(0xEE);   
    
    write_spi_command(POWER_CONTROL_6);   // POWER CONTROL 6   
    write_spi_data(0x0E);   

    write_spi_command(INVOFF);   
    
    write_spi_command(ORIENTATION);   // ORIENTATION   
    write_spi_data(0xC8);   
    
    write_spi_command(COLOR_MODE);
    write_spi_data(0x05);   
    
    write_spi_command(COLUMN_ADDR_SET);
    write_spi_data(0x00);   
    write_spi_data(0x00);  
    write_spi_data(0x00);   
    write_spi_data(0x7F);   
    
    write_spi_command(ROW_ADDR_SET);   // ROW ADDR SET   
    write_spi_data(0x00); 
    write_spi_data(0x00);
    write_spi_data(0x00); 
    write_spi_data(0x9F);


    write_spi_command(0xE0);
    write_spi_data(0x02);
    write_spi_data(0x1c);
    write_spi_data(0x07);
    write_spi_data(0x12);
    write_spi_data(0x37);
    write_spi_data(0x32);
    write_spi_data(0x29);
    write_spi_data(0x2d);
    write_spi_data(0x29);
    write_spi_data(0x25);
    write_spi_data(0x2B);
    write_spi_data(0x39);
    write_spi_data(0x00);
    write_spi_data(0x01);
    write_spi_data(0x03);
    write_spi_data(0x10);
    write_spi_command(0xE1);
    write_spi_data(0x03);
    write_spi_data(0x1d);
    write_spi_data(0x07);
    write_spi_data(0x06);
    write_spi_data(0x2E);
    write_spi_data(0x2C);
    write_spi_data(0x29);
    write_spi_data(0x2D);
    write_spi_data(0x2E);
    write_spi_data(0x2E);
    write_spi_data(0x37);
    write_spi_data(0x3F);
    write_spi_data(0x00);
    write_spi_data(0x00);
    write_spi_data(0x02);
    write_spi_data(0x10);

    write_spi_command(DISPLAY_ON); // display ON
    wait_ms(100);

    write_spi_command(NORMAL_DISP_ON);  // normal display on
    wait_ms(10);

    pwm.period_ms(2);

    // just increasing the brightness of the screen gradually
    for(float i = 0.0f; i < 1.0f; i += 0.1f) 
    {
        wait_ms(200);
        pwm = i;
    }

    console.printf("PWM done\n"); // here for debugging

}

inline int gen_helper::spiwrite(uint8_t c) 
{
    return lcd.write(c);
    
}

/* Write command */
void gen_helper::write_spi_command(uint8_t c) 
{

    rs = 0;
    ssel = 0;
    lcd.write(c);
    ssel = 1;
}

/* Write data */
void gen_helper::write_spi_data(uint8_t c) 
{

    rs = 1;
    ssel = 0;    
    lcd.write(c);
    ssel = 1;

} 

/**
 * Based on ST7735 source ; sets the screen co-ordinates
*/
void gen_helper::set_screen_coor(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) 
{

  write_spi_command(COLUMN_ADDR_SET); // Column addr set
  write_spi_data(0x00);
  write_spi_data(x0+colstart);     // XSTART 
  write_spi_data(0x00);
  write_spi_data(x1+colstart);     // XEND

  write_spi_command(ROW_ADDR_SET); // Row addr set
  write_spi_data(0x00);
  write_spi_data(y0+rowstart);     // YSTART
  write_spi_data(0x00);
  write_spi_data(y1+rowstart);     // YEND

  write_spi_command(WRITE_RAM); // write to RAM
}


/**
* Draw a pixel on the screen
*/
void gen_helper::draw_pixel(int16_t x, int16_t y, uint16_t color) {

    // exit if the co-ordinates are out of bounds of the screen
    if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height))
        return;

  set_screen_coor(x, y, x + 1, y + 1);
  
  rs = 1; 
  ssel = 0;
  lcd.format(16,3); //set the data rate to 16 bits
  lcd.write(color);     
  ssel = 1;
  lcd.format(8,3); //set the data rate to 8 bits
}

/**
* Draw a vertical line
* Based on ST7735 source
*/
void gen_helper::draw_vertical_line(int16_t x, int16_t y, int16_t h, uint16_t color) 
{

    if((x >= _width) || (y >= _height))
        return;

    if((y + h - 1) >= _height)
        h = _height - y;

    set_screen_coor(x, y, x, y + h - 1);

    uint8_t hi = color >> 8, lo = color;
    while (h--) 
    {
        spiwrite(hi);
        spiwrite(lo);
    }
}

/**
* Draw a horizontal line
* Based on ST7735 source
*/
void gen_helper::draw_horizontal_line(int16_t x, int16_t y, int16_t w, uint16_t color) 
{

    //check for screen boundary
    if((x >= _width) || (y >= _height))
        return;

    if((x + w - 1) >= _width)
        w = _width - x;

    set_screen_coor(x, y, x + w - 1, y);

    uint8_t hi = color >> 8, lo = color;

    while (w--) {
        spiwrite(hi);
        spiwrite(lo);
    }
}

/**
* Draw a rectangle and fill it with a color
*/
void gen_helper::fill_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t color)
{
    int16_t width, height;

    width = x1 - x0 + 1;
    height = y1 - y0 + 1;
    set_screen_coor(x0, y0, x1, y1);
    write_spi_command(WRITE_RAM);
    write_rgb(color, width * height);
}

/**
* Write RGB colors to the screen
*/
void gen_helper::write_rgb(uint32_t color, uint32_t repeat) {
    
    uint8_t red, green, blue;
    int i;
    red = (color >> 16);
    green = (color >> 8) & 0xFF;
    blue = color & 0xFF;
    
    for (i = 0; i< repeat; i++) 
    {
        write_spi_data(red);
        write_spi_data(green);
        write_spi_data(blue);
    }
}