Post It

Dependencies:   LM75B

Fork of EM027BS013 by EmbeddedArtists AB

EPD_COG_process_v230_G2.cpp

Committer:
ShalajLawania
Date:
2014-12-09
Revision:
1:3700ccf919d8
Parent:
0:9297e33f50cf

File content as of revision 1:3700ccf919d8:

/**
* \file
*
* \brief The waveform driving processes and updating stages of G2 COG with V230 EPD
*
* Copyright (c) 2012-2014 Pervasive Displays Inc. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
*    Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
**/

#include "EPD_COG_process.h"
#ifdef COG_V230_G2

#define ADDRESS_NULL		0xffffffff
//EPD Panel parameters
const struct COG_parameters_t COG_parameters[COUNT_OF_EPD_TYPE]  = {
	{
		// FOR 1.44"
		{0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00},
		0x03,
		(128/8),
		96,
		((((128+96)*2)/8)+1),
		0,
		480
	},
	{
		// For 2.0"
		{0x00,0x00,0x00,0x00,0x01,0xFF,0xE0,0x00},
		0x03,
		(200/8),
		96,
		((((200+96)*2)/8)+1),
		0,
		480
	},
	{
		// For 2.7"
		{0x00,0x00,0x00,0x7F,0xFF,0xFE,0x00,0x00},
		0x00,
		(264/8),
		176,
		((((264+176)*2)/8)+1),
		0,
		630
	}
};

/* \brief EPD Waveform parameters
 * \note the parameters of waveform table below is different from the G2 COG document due to
 *       use block size is easier to achieve than accurate block time for different MCU.
 *       The approach is also working.
 * */
 const struct EPD_WaveformTable_Struct E_Waveform[COUNT_OF_EPD_TYPE][3]  = {
		{// FOR 1.44"
			{//50 �� T �� 40
				4,				//stage1_frame1
				16,				//stage1_block1
				2,				//stage1_step1				
				155,			//stage2_t1
				155,			//stage2_t2
				4,				//stage2_cycle
				4,				//stage3_frame3
				16,				//stage3_block3
				2				//stage3_step3
			}
			,{//40 �� T �� 10
				4,				//stage1_frame1
				16,				//stage1_block1
				2,				//stage1_step1				
				155,			//stage2_t1
				155,			//stage2_t2
				4,				//stage2_cycle
				4,				//stage3_frame3
				16,				//stage3_block3
				2				//stage3_step3
			},
			{//10 �� T �� 0
				2,				//stage1_frame1
				42,				//stage1_block1
				6,				//stage1_step1
				392,			//stage2_t1
				392,			//stage2_t2
				4,				//stage2_cycle
				2,				//stage3_frame3
				42,				//stage3_block3
				6				//stage3_step3
			}
			
		},
		{// For 2.0"
			{//50 �� T �� 40
				4,				//stage1_frame1
				36,				//stage1_block1
				2,				//stage1_step1				
				196,			//stage2_t1
				196,			//stage2_t2
				4,				//stage2_cycle
				4,				//stage3_frame3
				36,				//stage3_block3
				2				//stage3_step3
			},
			{//40 �� T �� 10
				2,				//stage1_frame1
				36,				//stage1_block1
				2,				//stage1_step1
				196,			//stage2_t1
				196,			//stage2_t2
				4,				//stage2_cycle
				2,				//stage3_frame3
				36,				//stage3_block3
				2				//stage3_step3
			},
			{//10 �� T �� 0
				2,				//stage1_frame1
				36,				//stage1_block1
				2,				//stage1_step1
				392,			//stage2_t1
				392,			//stage2_t2
				4,				//stage2_cycle
				2,				//stage3_frame3
				36,				//stage3_block3
				2				//stage3_step3
			}
		},
		{// For 2.7"
			{//50 �� T �� 40
				4,				//stage1_frame1
				28,				//stage1_block1
				4,				//stage1_step1
				196,			//stage2_t1
				196,			//stage2_t2
				4,				//stage2_cycle
				4,				//stage3_frame3
				28,				//stage3_block3
				4				//stage3_step3
			},
			{//40 �� T �� 10
				2,				//stage1_frame1
				28,				//stage1_block1
				2,				//stage1_step1
				196,			//stage2_t1
				196,			//stage2_t2
				4,				//stage2_cycle
				2,				//stage3_frame3
				28,				//stage3_block3
				2				//stage3_step3
			},
			{//10 �� T �� 0
				2,				//stage1_frame1
				28,				//stage1_block1
				4,				//stage1_step1
				392,			//stage2_t1
				392,			//stage2_t2
				4,				//stage2_cycle
				2,				//stage3_frame3
				28,				//stage3_block3
				4				//stage3_step3
			}
		},
	 
 };

const uint8_t   SCAN_TABLE[4] = {0xC0,0x30,0x0C,0x03};
	
static struct EPD_WaveformTable_Struct *action__Waveform_param;
static COG_line_data_packet_type COG_Line;
static EPD_read_flash_handler _On_EPD_read_flash;
static uint8_t  *data_line_even;
static uint8_t  *data_line_odd;
static uint8_t  *data_line_scan;
static uint8_t  *data_line_border_byte;

/**
* \brief According to EPD size and temperature to get stage_time
* \note Refer to COG document Section 5.3 for more details
*
* \param EPD_type_index The defined EPD size
*/
static void set_temperature_factor(uint8_t EPD_type_index) {
	int8_t temperature;
	temperature = get_temperature();	
        if (50 >= temperature  && temperature > 40){
			action__Waveform_param=(struct EPD_WaveformTable_Struct *)&E_Waveform[EPD_type_index][0];
		}else if (40 >= temperature  && temperature > 10){
			action__Waveform_param=(struct EPD_WaveformTable_Struct *)&E_Waveform[EPD_type_index][1];
		}else if (10 >= temperature  && temperature > 0){
			action__Waveform_param=(struct EPD_WaveformTable_Struct *)&E_Waveform[EPD_type_index][2];
		}else action__Waveform_param=(struct EPD_WaveformTable_Struct *)&E_Waveform[EPD_type_index][0]; //Default
}

/**
* \brief Initialize the EPD hardware setting
*/
void EPD_init(void) {
	EPD_display_hardware_init();
	EPD_cs_low();
	EPD_rst_low();
	EPD_discharge_low();
	EPD_border_low();
}

/**
* \brief Select the EPD size to get line data array for driving COG
*
* \param EPD_type_index The defined EPD size
*/
void COG_driver_EPDtype_select(uint8_t EPD_type_index) {
	switch(EPD_type_index) {
		case EPD_144:
		data_line_even = &COG_Line.line_data_by_size.line_data_for_144.even[0];
		data_line_odd  = &COG_Line.line_data_by_size.line_data_for_144.odd[0];
		data_line_scan = &COG_Line.line_data_by_size.line_data_for_144.scan[0];
		data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_144.border_byte;
		break;
		case EPD_200:
		data_line_even = &COG_Line.line_data_by_size.line_data_for_200.even[0];
		data_line_odd  = &COG_Line.line_data_by_size.line_data_for_200.odd[0];
		data_line_scan = &COG_Line.line_data_by_size.line_data_for_200.scan[0];
		data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_200.border_byte;
		break;
		case EPD_270:
		data_line_even = &COG_Line.line_data_by_size.line_data_for_270.even[0];
		data_line_odd  = &COG_Line.line_data_by_size.line_data_for_270.odd[0];
		data_line_scan = &COG_Line.line_data_by_size.line_data_for_270.scan[0];
		data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_270.border_byte;
		break;
	}
}

/**
* \brief Power on COG Driver
* \note For detailed flow and description, please refer to the COG G2 document Section 3.
*/
void EPD_power_on (void) {	
	/* Initial state */
	EPD_Vcc_turn_on(); //Vcc and Vdd >= 2.7V	
	EPD_cs_high();
	EPD_border_high();
	EPD_rst_high();
	//delay_ms(1);	
	EPD_rst_low();
	//delay_ms(1);
	EPD_rst_high();
	//delay_ms(1);
}


/**
* \brief Initialize COG Driver
* \note For detailed flow and description, please refer to the COG G2 document Section 4.
*
* \param EPD_type_index The defined EPD size
*/
uint8_t EPD_initialize_driver (uint8_t EPD_type_index) {
	
	uint16_t i;
	// Empty the Line buffer
	for (i = 0; i <= LINE_BUFFER_DATA_SIZE; i ++) {
		COG_Line.uint8[i] = 0x00;
	}
	// Determine the EPD size for driving COG
	COG_driver_EPDtype_select(EPD_type_index);

	// Sense temperature to determine Temperature Factor
	set_temperature_factor(EPD_type_index);
	i = 0;
	
	while (EPD_IsBusy()) {
		if((i++) >= 0x0FFF) return ERROR_BUSY;
	}
	
	//Check COG ID
	if((SPI_R(0x72,0x00) & 0x0f) !=0x02) return ERROR_COG_ID;

	//Disable OE
	epd_spi_send_byte(0x02,0x40);	

	//Check Breakage
	if((SPI_R(0x0F,0x00) & 0x80) != 0x80) return ERROR_BREAKAGE;
	
	//Power Saving Mode
 	epd_spi_send_byte(0x0B, 0x02);

	//Channel Select
	epd_spi_send (0x01, (uint8_t *)&COG_parameters[EPD_type_index].channel_select, 8);

	//High Power Mode Osc Setting
	epd_spi_send_byte(0x07,0xD1);

	//Power Setting
	epd_spi_send_byte(0x08,0x02);

	//Set Vcom level
	epd_spi_send_byte(0x09,0xC2);

	//Power Setting
	epd_spi_send_byte(0x04,0x03);

	//Driver latch on
	epd_spi_send_byte(0x03,0x01);

	//Driver latch off
	epd_spi_send_byte(0x03,0x00);

	delay_ms(5);

	//Chargepump Start
	i=0;
	do {
		//Start chargepump positive V
		//VGH & VDH on
		epd_spi_send_byte(0x05,0x01);

		delay_ms(240);

		//Start chargepump neg voltage
		//VGL & VDL on
		epd_spi_send_byte(0x05,0x03);

		delay_ms(40);

		//Set chargepump
		//Vcom_Driver to ON
		//Vcom_Driver on
		epd_spi_send_byte(0x05,0x0F);

		delay_ms(40);

		//Check DC/DC
		if((SPI_R(0x0F,0x00) & 0x40) != 0x00) break;	
		
	}while((i++) != 4);
	
	if(i>=4) 
	{
		//Output enable to disable
		epd_spi_send_byte(0x02,0x40);
		return ERROR_CHARGEPUMP;
	}
	else  return RES_OK;
}

/**
* \brief Initialize the parameters of Block type stage 
*
* \param EPD_type_index The defined EPD size
* \param EPD_V230_G2_Struct The Block type waveform structure
* \param block_size The width of Block size
* \param step_size The width of Step size
* \param frame_cycle The width of Step size
*/
void stage_init(uint8_t EPD_type_index,struct EPD_V230_G2_Struct *S_epd_v230,
				uint8_t block_size,uint8_t step_size,
				uint8_t frame_cycle)
{
	S_epd_v230->frame_y0 = 0;
	S_epd_v230->frame_y1 = 176;
	S_epd_v230->block_y0 = 0;
	S_epd_v230->block_y1 = 0;
	S_epd_v230->step_y0 = 0;
	S_epd_v230->step_y1 = 0;
	S_epd_v230->block_size = action__Waveform_param->stage1_block1;
	S_epd_v230->step_size =action__Waveform_param->stage1_step1;
	S_epd_v230->frame_cycle = action__Waveform_param->stage1_frame1;
	S_epd_v230->number_of_steps = (COG_parameters[EPD_type_index].vertical_size / S_epd_v230->step_size) + (action__Waveform_param->stage1_block1 / action__Waveform_param->stage1_step1) -1;
	
}

/**
* \brief For Frame type waveform to update all black/white pattern
*
* \param EPD_type_index The defined EPD size
* \param bwdata Black or White color to whole screen
* \param work_time The working time
*/
static inline void same_data_frame (uint8_t EPD_type_index, uint8_t bwdata, uint32_t work_time) {
	uint16_t i;
	for (i = 0; i <  COG_parameters[EPD_type_index].horizontal_size; i++) {
		data_line_even[i]=bwdata;
		data_line_odd[i]=bwdata;
	}
	start_EPD_timer();
	do 
	{	
		for (i = 0; i < COG_parameters[EPD_type_index].vertical_size; i++) {
			
			/* Scan byte shift per data line */
			data_line_scan[(i>>2)]=SCAN_TABLE[(i%4)];
			
			/* Sending data */
			epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8, COG_parameters[EPD_type_index].data_line_size);
		 
			/* Turn on Output Enable */
			epd_spi_send_byte (0x02, 0x07);
		
			data_line_scan[(i>>2)]=0;
			
		}
	} while (get_current_time_tick()<(work_time));
		/* Stop system timer */
		stop_EPD_timer();
}

/**
* \brief Write nothing Line to COG
* \note A line whose all Scan Bytes are 0x00
*
* \param EPD_type_index The defined EPD size
*/
void nothing_line(uint8_t EPD_type_index) {
	uint16_t i;
	for (i = 0; i <  COG_parameters[EPD_type_index].horizontal_size; i++) {
		data_line_even[i]	=	NOTHING;
		data_line_odd[i]	=	NOTHING;
	}
}


/**
* \brief Get line data of Stage 1 and 3
*
* \note
* - One dot/pixel is comprised of 2 bits which are White(10), Black(11) or Nothing(01).
*   The image data bytes must be divided into Odd and Even bytes.
* - The COG driver uses a buffer to write one line of data (FIFO) - interlaced
*   It's different order from COG_G1
*   Odd byte {D(199,y),D(197,y), D(195,y), D(193,y)}, ... ,{D(7,y),D(5,y),D(3,y), D(1,y)}
*   Scan byte {S(96), S(95)...}
*   Odd byte  {D(2,y),D(4,y), D(6,y), D(8,y)}, ... ,{D(194,y),D(196,y),D(198,y), D(200,y)}
* - For more details on the driving stages, please refer to the COG G2 document Section 5.
*
* \param EPD_type_index The defined EPD size
* \param image_ptr The pointer of memory that stores image that will send to COG
* \param stage_no The assigned stage number that will proceed
*/

void read_line_data_handle(uint8_t EPD_type_index,uint8_t *image_prt,uint8_t stage_no)
{
	int16_t x,k;
	uint8_t	temp_byte; // Temporary storage for image data check
	k=COG_parameters[EPD_type_index].horizontal_size-1;	
	for (x =0 ; x < COG_parameters[EPD_type_index].horizontal_size ; x++) {
				temp_byte = *image_prt++;
				switch(stage_no) {
					case Stage1: // Inverse image
					/* Example at stage 1 to get Even and Odd data. It's different order from G1.
					* +---------+----+----+----+----+----+----+----+----+
					* |         |bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0|
					* |temp_byte+----+----+----+----+----+----+----+----+
					* |         |  1 |  0 |  1 |  1 |  0 |  1 |  0 |  0 |
					* +---------+----+----+----+----+----+----+----+----+ */
					data_line_odd[x]       = ((temp_byte & 0x40) ? BLACK3  : WHITE3); // WHITE3 = 0x80 = 1000 0000
					data_line_odd[x]      |= ((temp_byte & 0x10) ? BLACK2  : WHITE2); // BLACK2 = 0x30 = 0011 0000
					data_line_odd[x]      |= ((temp_byte & 0x04) ? BLACK1  : WHITE1); // BLACK1 = 0x0C = 0000 1100
					data_line_odd[x]	  |= ((temp_byte & 0x01) ? BLACK0  : WHITE0); // WHITE0 = 0x02 = 0000 0010
					/* data_line_odd[x] = 1000 0000 | 0011 0000 | 0000 1100 | 0000 0010 = 1011 1110 ==> 1011 1110
					* See Even data row at the table below*/
					
					data_line_even[k]    = ((temp_byte & 0x80) ? BLACK0  : WHITE0); // BLACK0 = 0x03 = 0000 0011
					data_line_even[k]   |= ((temp_byte & 0x20) ? BLACK1  : WHITE1); // BLACK1 = 0x0C = 0000 1100
					data_line_even[k]   |= ((temp_byte & 0x08) ? BLACK2  : WHITE2); // WHITE2 = 0x20 = 0010 0000
					data_line_even[k--] |= ((temp_byte & 0x02) ? BLACK3  : WHITE3); // WHITE3 = 0x80 = 1000 0000
					/* data_line_even[k] = 0000 0011 | 0000 1100 | 0010 0000 | 1000 0000 = 1010 1111 ==> 1111 1010
					* See Odd data row at the table below
					* +---------+----+----+----+----+----+----+----+----+
					* |         |bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0|
					* |temp_byte+----+----+----+----+----+----+----+----+
					* |         |  1 |  0 |  1 |  1 |  0 |  1 |  0 |  0 |
					* +---------+----+----+----+----+----+----+----+----+
					* | Color   |  W |  B |  W |  W |  B |  W |  B |  B | W=White, B=Black, N=Nothing
					* +---------+----+----+----+----+----+----+----+----+
					* | Stage 1 |  B |  W |  B |  B |  W |  B |  W |  W | Inverse
					* +---------+----+----+----+----+----+----+----+----+
					* | Input   | 11 | 10 | 11 | 11 | 10 | 11 | 10 | 10 | W=10, B=11, N=01
					* +---------+----+----+----+----+----+----+----+----+
					* |Even data| 11 |    | 11 |    | 10 |    | 10 |    | = 1111 1010
					* +---------+----+----+----+----+----+----+----+----+
					* |Odd data |    | 10 |    | 11 |    | 11 |    | 10 | = 1011 1110
					* +---------+----+----+----+----+----+----+----+----+ */
					break;				
					case Stage3: // New image
						data_line_odd[x]		 = ((temp_byte & 0x40) ? WHITE3  : BLACK3 );
						data_line_odd[x]		|= ((temp_byte & 0x10) ? WHITE2  : BLACK2 );
						data_line_odd[x]		|= ((temp_byte & 0x04) ? WHITE1  : BLACK1 );
						data_line_odd[x]		|= ((temp_byte & 0x01) ? WHITE0  : BLACK0 );

						data_line_even[k]		 = ((temp_byte & 0x80) ? WHITE0  : BLACK0 );
						data_line_even[k]		|= ((temp_byte & 0x20) ? WHITE1  : BLACK1 );
						data_line_even[k]		|= ((temp_byte & 0x08) ? WHITE2  : BLACK2 );
						data_line_even[k--]		|= ((temp_byte & 0x02) ? WHITE3  : BLACK3 );
					break;
				}
		}	
}


/**
* \brief The base function to handle the driving stages for Frame and Block type
*
* \note
* - There are 3 stages to complete an image update on COG_V230_G2 type EPD.
* - For more details on the driving stages, please refer to the COG G2 document Section 5.4
*
* \param EPD_type_index The defined EPD size
* \param image_ptr The pointer of image array that stores image that will send to COG
* \param image_data_address The address of memory that stores image
* \param stage_no The assigned stage number that will proceed
* \param lineoffset Line data offset
*/
void stage_handle_Base(uint8_t EPD_type_index,uint8_t *image_prt,long image_data_address,
						uint8_t stage_no,uint8_t lineoffset)
{	
	struct EPD_V230_G2_Struct S_epd_v230;
	int16_t cycle,m,i; //m=number of steps
	//uint8_t isLastframe = 0;	//If it is the last frame to send Nothing at the fist scan line
	uint8_t isLastBlock=0;		//If the beginning line of block is in active range of EPD
	int16_t scanline_no=0;
	uint8_t *action_block_prt;
	long action_block_address;
	uint8_t byte_array[LINE_BUFFER_DATA_SIZE];
	/** Stage 2: BLACK/WHITE image, Frame type */
	if(stage_no==Stage2)
	{
		for(i=0;i<action__Waveform_param->stage2_cycle;i++)
		{
			same_data_frame (EPD_type_index,ALL_BLACK,action__Waveform_param->stage2_t1);
			same_data_frame (EPD_type_index,ALL_WHITE,action__Waveform_param->stage2_t2);
		}
		return;
	}
	/** Stage 1 & 3, Block type */
	// The frame/block/step of Stage1 and Stage3 are default the same.
	stage_init(EPD_type_index,
				&S_epd_v230,
				action__Waveform_param->stage1_block1,
				action__Waveform_param->stage1_step1,
				action__Waveform_param->stage1_frame1);
	 
	 /* Repeat number of frames */
   	 for (cycle = 0; cycle < (S_epd_v230.frame_cycle ); cycle++)
   	 {
		
	    // if (cycle == (S_epd_v230.frame_cycle - 1)) isLastframe = 1;
		 
		 isLastBlock = 0;
		 S_epd_v230.step_y0 = 0;
		 S_epd_v230.step_y1 = S_epd_v230.step_size ;
		 S_epd_v230.block_y0 = 0;
		 S_epd_v230.block_y1 = 0;
		 /* Move number of steps */
	   	 for (m = 0; m < S_epd_v230.number_of_steps; m++)	 
	   	 {		   	
			 S_epd_v230.block_y1 += S_epd_v230.step_size;
			 S_epd_v230.block_y0 = S_epd_v230.block_y1 - S_epd_v230.block_size;
			/* reset block_y0=frame_y0 if block is not in active range of EPD */
		   	 if (S_epd_v230.block_y0 < S_epd_v230.frame_y0) S_epd_v230.block_y0 = S_epd_v230.frame_y0;
			
			/* if the beginning line of block is in active range of EPD */
			 if (S_epd_v230.block_y1 == S_epd_v230.block_size) isLastBlock = 1;
			 	
			 if(image_prt!=NULL)
			 {
				 action_block_prt=(image_prt+(int)(S_epd_v230.block_y0*lineoffset));	
			 }
			 else if(_On_EPD_read_flash!=NULL)	//Read line data in range of block, read first
			 {
				action_block_address=image_data_address+(long)(S_epd_v230.block_y0*lineoffset);
				_On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
									COG_parameters[EPD_type_index].horizontal_size);
				action_block_prt=(uint8_t *)&byte_array;
			 }	
			/* Update line data */
		   	 for (i = S_epd_v230.block_y0; i < S_epd_v230.block_y1; i++)
		   	 {		
				
			     if (i >= COG_parameters[EPD_type_index].vertical_size) break;
				 //if (isLastframe && 
				 if ( 
				  isLastBlock &&(i < (S_epd_v230.step_size + S_epd_v230.block_y0)))
				  {
					  nothing_line(EPD_type_index);					
				  }
				  else	 
				  {			  					 
					  read_line_data_handle(EPD_type_index,action_block_prt,stage_no);					
				  }
			   		
				if(_On_EPD_read_flash!=NULL)	//Read line data in range of block
				{
					action_block_address +=lineoffset;
					_On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
					COG_parameters[EPD_type_index].horizontal_size);
					action_block_prt=(uint8_t *)&byte_array;
				}
				else action_block_prt+=lineoffset;
					
				scanline_no= (COG_parameters[EPD_type_index].vertical_size-1)-i;
					
				/* Scan byte shift per data line */
				data_line_scan[(scanline_no>>2)] = SCAN_TABLE[(scanline_no%4)];
				   
				/*  the border uses the internal signal control byte. */
				*data_line_border_byte=0x00;
					   
				/* Sending data */
				epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8,
				COG_parameters[EPD_type_index].data_line_size);
				
					 
				/* Turn on Output Enable */
				epd_spi_send_byte (0x02, 0x07);
					   
				data_line_scan[(scanline_no>>2)]=0;		
										
		   	 }												
	   	 }
			
    }	
}

/**
* \brief The driving stages from image array (image_data.h) to COG
*
* \param EPD_type_index The defined EPD size
* \param image_ptr The pointer of image array that stores image that will send to COG
* \param stage_no The assigned stage number that will proceed
* \param lineoffset Line data offset
*/
void stage_handle(uint8_t EPD_type_index,uint8_t *image_prt,uint8_t stage_no,uint8_t lineoffset)
{
	stage_handle_Base(EPD_type_index,image_prt,ADDRESS_NULL,stage_no,lineoffset);	
}

/**
* \brief The driving stages from memory to COG
*
* \note
* - This function is additional added here for developer if the image data
*   is stored in Flash memory.
*
* \param EPD_type_index The defined EPD size
* \param image_data_address The address of flash memory that stores image
* \param stage_no The assigned stage number that will proceed
* \param lineoffset Line data offset
*/
static void stage_handle_ex(uint8_t EPD_type_index,long image_data_address,uint8_t stage_no,uint8_t lineoffset) {
	stage_handle_Base(EPD_type_index,NULL,image_data_address,stage_no,lineoffset);
}

/**
* \brief Write image data from memory array (image_data.h) to the EPD
*
* \param EPD_type_index The defined EPD size
* \param previous_image_ptr The pointer of memory that stores previous image
* \param new_image_ptr The pointer of memory that stores new image
*/
void EPD_display_from_array_prt (uint8_t EPD_type_index, uint8_t *previous_image_ptr,
		uint8_t *new_image_ptr) {	
	_On_EPD_read_flash=0;
	stage_handle(EPD_type_index,new_image_ptr,Stage1,COG_parameters[EPD_type_index].horizontal_size);	
	stage_handle(EPD_type_index,new_image_ptr,Stage2,COG_parameters[EPD_type_index].horizontal_size);	
	stage_handle(EPD_type_index,new_image_ptr,Stage3,COG_parameters[EPD_type_index].horizontal_size);	
}

/**
* \brief Write image data from Flash memory to the EPD
* \note This function is additional added here for developer if the image data
* is stored in Flash.
*
* \param EPD_type_index The defined EPD size
* \param previous_image_flash_address The start address of memory that stores previous image
* \param new_image_flash_address The start address of memory that stores new image
* \param On_EPD_read_flash Developer needs to create an external function to read flash
*/
void EPD_display_from_flash_prt (uint8_t EPD_type_index, long previous_image_flash_address,
    long new_image_flash_address,EPD_read_flash_handler On_EPD_read_flash) {
		
	uint8_t line_len;
	line_len=LINE_SIZE;
	if(line_len==0) line_len=COG_parameters[EPD_type_index].horizontal_size;
		
	_On_EPD_read_flash=On_EPD_read_flash;	
	stage_handle_ex(EPD_type_index,new_image_flash_address,Stage1,line_len);
	stage_handle_ex(EPD_type_index,new_image_flash_address,Stage2,line_len);
	stage_handle_ex(EPD_type_index,new_image_flash_address,Stage3,line_len);	
}


/**
* \brief Write Dummy Line to COG
* \note A line whose all Scan Bytes are 0x00
*
* \param EPD_type_index The defined EPD size
*/
static inline void dummy_line(uint8_t EPD_type_index) {
	uint8_t	i;
	for (i = 0; i < (COG_parameters[EPD_type_index].vertical_size/8); i++) {
		switch(EPD_type_index) {
			case EPD_144:
			COG_Line.line_data_by_size.line_data_for_144.scan[i]=0x00;
			break;
			case EPD_200:
			COG_Line.line_data_by_size.line_data_for_200.scan[i]=0x00;
			break;
			case EPD_270:
			COG_Line.line_data_by_size.line_data_for_270.scan[i]=0x00;
			break;
		}
	}
	/* Set charge pump voltage level reduce voltage shift */
	epd_spi_send_byte (0x04, COG_parameters[EPD_type_index].voltage_level);
	
	/* Sending data */
	epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8, COG_parameters[EPD_type_index].data_line_size);

	/* Turn on Output Enable */
	epd_spi_send_byte (0x02, 0x07);
}


/**
* \brief Write Border(Input) Dummy Line
* \note Set Border byte 0xFF to write Black and set 0xAA to write White
*
* \param EPD_type_index The defined EPD size
*/
static void border_dummy_line(uint8_t EPD_type_index)
{
	uint16_t	i;
	for (i = 0; i < COG_parameters[EPD_type_index].data_line_size; i++)
	{
		COG_Line.uint8[i] = 0x00;
	}
	
	*data_line_border_byte=BORDER_BYTE_B;
	//Write a Border(B) Dummy Line
	epd_spi_send (0x0a, (uint8_t *)&COG_Line.uint8, COG_parameters[EPD_type_index].data_line_size);
	//Turn on OE
	epd_spi_send_byte (0x02, 0x07);
	
	sys_delay_ms(40);
	
	*data_line_border_byte=BORDER_BYTE_W;
	//Write a Borde(B) Dummy Line
	epd_spi_send (0x0a, (uint8_t *)&COG_Line.uint8, COG_parameters[EPD_type_index].data_line_size);
	//Turn on OE
	epd_spi_send_byte (0x02, 0x07);

	sys_delay_ms(200);
	
	
}


/**
* \brief Power Off COG Driver
* \note For detailed flow and description, please refer to the COG G2 document Section 6.
*
* \param EPD_type_index The defined EPD size
*/
uint8_t EPD_power_off(uint8_t EPD_type_index) {
	uint8_t y;		

	if(EPD_type_index==EPD_144 || EPD_type_index==EPD_200) 	{
		border_dummy_line(EPD_type_index);
		dummy_line(EPD_type_index);
	}

	//delay_ms (25);
	if(EPD_type_index==EPD_270)	{
		EPD_border_low();
		//delay_ms (200);
		EPD_border_high();
	}

	//Check DC/DC
	if((SPI_R(0x0F,0x00) & 0x40) == 0x00) return ERROR_DC;
	
	//Turn on Latch Reset
	epd_spi_send_byte (0x03, 0x01);
	//Turn off OE
	epd_spi_send_byte (0x02, 0x05);
	//Power off charge pump Vcom
	epd_spi_send_byte (0x05, 0x0E);
	//Power off charge pump neg voltage
	epd_spi_send_byte (0x05, 0x02);
	//Turn off all charge pump 
	epd_spi_send_byte (0x05, 0x00);
	//Turn off OSC
	epd_spi_send_byte (0x07, 0x0D);
	
	epd_spi_send_byte (0x04, 0x83);
	delay_ms(80);
	epd_spi_send_byte (0x04, 0x00);
	
	epd_spi_detach ();
	EPD_cs_low();
	EPD_rst_low();
	EPD_Vcc_turn_off ();
	EPD_border_low();
	//delay_ms (10);
		
	for(y=0;y<10;y++)
	{
		EPD_discharge_high ();		
		//delay_ms (10);		
		EPD_discharge_low ();	
		//delay_ms (10);	
	}
	return RES_OK;
}

#endif