 5c81bb8abc
			
		
	
	
		5c81bb8abc
		
			
		
	
	
	
	
		
			
			* add u8g2 and ui libs * add display driver and usage example * not init display in test mode * change todo text * fix removed code * Target f2 (#107) * add ioc for flipperzero f2 * add generated f1 files to f2 * regenerate cubemx * invert initial state of led * blink backligh * shutdown backlight on idle
		
			
				
	
	
		
			667 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			667 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| 
 | |
|   u8x8_byte.c 
 | |
|   
 | |
|   Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
 | |
| 
 | |
|   Copyright (c) 2016, olikraus@gmail.com
 | |
|   All rights reserved.
 | |
| 
 | |
|   Redistribution and use in source and binary forms, with or without modification, 
 | |
|   are permitted provided that the following conditions are met:
 | |
| 
 | |
|   * Redistributions of source code must retain the above copyright notice, this list 
 | |
|     of conditions and the following disclaimer.
 | |
|     
 | |
|   * 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.
 | |
| 
 | |
|   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
 | |
|   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
 | |
|   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 | |
|   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 | |
|   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 | |
|   CONTRIBUTORS 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.  
 | |
|   
 | |
|   
 | |
| */
 | |
| 
 | |
| #include "u8x8.h"
 | |
| 
 | |
| uint8_t u8x8_byte_SetDC(u8x8_t *u8x8, uint8_t dc)
 | |
| {
 | |
|   return u8x8->byte_cb(u8x8, U8X8_MSG_BYTE_SET_DC, dc, NULL);
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_SendBytes(u8x8_t *u8x8, uint8_t cnt, uint8_t *data)
 | |
| {
 | |
|   return u8x8->byte_cb(u8x8, U8X8_MSG_BYTE_SEND, cnt, (void *)data);
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_SendByte(u8x8_t *u8x8, uint8_t byte)
 | |
| {
 | |
|   return u8x8_byte_SendBytes(u8x8, 1, &byte);
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_StartTransfer(u8x8_t *u8x8)
 | |
| {
 | |
|   return u8x8->byte_cb(u8x8, U8X8_MSG_BYTE_START_TRANSFER, 0, NULL);
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_EndTransfer(u8x8_t *u8x8)
 | |
| {
 | |
|   return u8x8->byte_cb(u8x8, U8X8_MSG_BYTE_END_TRANSFER, 0, NULL);
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| uint8_t u8x8_byte_empty(U8X8_UNUSED u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
 | |
| {
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       break;	/* do nothing */
 | |
|   }
 | |
|   return 1;	/* always succeed */
 | |
| }
 | |
| 
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Uses:
 | |
|     u8x8->display_info->sda_setup_time_ns
 | |
|     u8x8->display_info->sck_pulse_width_ns
 | |
|     u8x8->display_info->spi_mode
 | |
|     u8x8->display_info->chip_disable_level
 | |
|     u8x8->display_info->chip_enable_level
 | |
|     u8x8->display_info->post_chip_enable_wait_ns
 | |
|     u8x8->display_info->pre_chip_disable_wait_ns
 | |
|   Calls to GPIO and DELAY:
 | |
|     U8X8_MSG_DELAY_NANO
 | |
|     U8X8_MSG_GPIO_DC
 | |
|     U8X8_MSG_GPIO_CS
 | |
|     U8X8_MSG_GPIO_CLOCK
 | |
|     U8X8_MSG_GPIO_DATA
 | |
|   Handles:
 | |
|     U8X8_MSG_BYTE_INIT
 | |
|     U8X8_MSG_BYTE_SEND
 | |
|     U8X8_MSG_BYTE_SET_DC
 | |
|     U8X8_MSG_BYTE_START_TRANSFER
 | |
|     U8X8_MSG_BYTE_END_TRANSFER
 | |
| */
 | |
| 
 | |
| uint8_t u8x8_byte_4wire_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i, b;
 | |
|   uint8_t *data;
 | |
|   uint8_t takeover_edge = u8x8_GetSPIClockPhase(u8x8);
 | |
|   uint8_t not_takeover_edge = 1 - takeover_edge;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = 0; i < 8; i++ )
 | |
| 	{
 | |
| 	  if ( b & 128 )
 | |
| 	    u8x8_gpio_SetSPIData(u8x8, 1);
 | |
| 	  else
 | |
| 	    u8x8_gpio_SetSPIData(u8x8, 0);
 | |
| 	  b <<= 1;
 | |
| 	  
 | |
| 	  u8x8_gpio_SetSPIClock(u8x8, not_takeover_edge);
 | |
| 	  u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->sda_setup_time_ns);
 | |
| 	  u8x8_gpio_SetSPIClock(u8x8, takeover_edge);
 | |
| 	  u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->sck_pulse_width_ns);
 | |
| 	}    
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       /* no wait required here */
 | |
|       
 | |
|       /* for SPI: setup correct level of the clock signal */
 | |
|       u8x8_gpio_SetSPIClock(u8x8, u8x8_GetSPIClockPhase(u8x8));
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       u8x8_gpio_SetDC(u8x8, arg_int);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);  
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| uint8_t u8x8_byte_8bit_6800mode(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i, b;
 | |
|   uint8_t *data;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = U8X8_MSG_GPIO_D0; i <= U8X8_MSG_GPIO_D7; i++ )
 | |
| 	{
 | |
| 	  u8x8_gpio_call(u8x8, i, b&1);
 | |
| 	  b >>= 1;
 | |
| 	}    
 | |
| 	
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 1);
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);    
 | |
|       /* ensure that the enable signal is high */
 | |
|       u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       u8x8_gpio_SetDC(u8x8, arg_int);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);  
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_8bit_8080mode(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i, b;
 | |
|   uint8_t *data;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = U8X8_MSG_GPIO_D0; i <= U8X8_MSG_GPIO_D7; i++ )
 | |
| 	{
 | |
| 	  u8x8_gpio_call(u8x8, i, b&1);
 | |
| 	  b >>= 1;
 | |
| 	}    
 | |
| 	
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 1);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);    
 | |
|       /* ensure that the enable signal is high */
 | |
|       u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 1);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       u8x8_gpio_SetDC(u8x8, arg_int);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);  
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| uint8_t u8x8_byte_3wire_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i;
 | |
|   uint8_t *data;
 | |
|   uint8_t takeover_edge = u8x8_GetSPIClockPhase(u8x8);
 | |
|   uint8_t not_takeover_edge = 1 - takeover_edge;
 | |
|   uint16_t b;
 | |
|   static uint8_t last_dc;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	if ( last_dc != 0 )
 | |
| 	  b |= 256;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = 0; i < 9; i++ )
 | |
| 	{
 | |
| 	  if ( b & 256 )
 | |
| 	    u8x8_gpio_SetSPIData(u8x8, 1);
 | |
| 	  else
 | |
| 	    u8x8_gpio_SetSPIData(u8x8, 0);
 | |
| 	  b <<= 1;
 | |
| 	  
 | |
| 	  u8x8_gpio_SetSPIClock(u8x8, not_takeover_edge);
 | |
| 	  u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->sda_setup_time_ns);
 | |
| 	  u8x8_gpio_SetSPIClock(u8x8, takeover_edge);
 | |
| 	  u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->sck_pulse_width_ns);
 | |
| 	}    
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       /* no wait required here */
 | |
|       
 | |
|       /* for SPI: setup correct level of the clock signal */
 | |
|       u8x8_gpio_SetSPIClock(u8x8, u8x8_GetSPIClockPhase(u8x8));
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       last_dc = arg_int;
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);  
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| void u8x8_byte_set_ks0108_cs(u8x8_t *u8x8, uint8_t arg)
 | |
| {
 | |
|   u8x8_gpio_SetCS(u8x8, arg&1);
 | |
|   arg = arg >> 1;
 | |
|   u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_CS1, arg&1);
 | |
|   arg = arg >> 1;
 | |
|   u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_CS2, arg&1);
 | |
| }
 | |
| 
 | |
| /* 6800 mode */
 | |
| uint8_t u8x8_byte_ks0108(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i, b;
 | |
|   uint8_t *data;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = U8X8_MSG_GPIO_D0; i <= U8X8_MSG_GPIO_D7; i++ )
 | |
| 	{
 | |
| 	  u8x8_gpio_call(u8x8, i, b&1);
 | |
| 	  b >>= 1;
 | |
| 	}    
 | |
| 	
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 1);
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
 | |
| 	u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);    
 | |
|       /* ensure that the enable signal is low */
 | |
|       u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       u8x8_gpio_SetDC(u8x8, arg_int);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       /* expects 3 bits in arg_int for the chip select lines */ 
 | |
|       u8x8_byte_set_ks0108_cs(u8x8, arg_int);
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
 | |
|       u8x8_byte_set_ks0108_cs(u8x8, arg_int);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* sed1520 or sbn1661 
 | |
|   U8X8_MSG_GPIO_E --> E1
 | |
|   U8X8_MSG_GPIO_CS --> E2
 | |
| */
 | |
| uint8_t u8x8_byte_sed1520(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t i, b;
 | |
|   uint8_t *data;
 | |
|   static uint8_t enable_pin;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	b = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
| 	for( i = U8X8_MSG_GPIO_D0; i <= U8X8_MSG_GPIO_D7; i++ )
 | |
| 	{
 | |
| 	  u8x8_gpio_call(u8x8, i, b&1);
 | |
| 	  b >>= 1;
 | |
| 	}    
 | |
| 	
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
 | |
| 	u8x8_gpio_call(u8x8, enable_pin, 1);
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, 200);		/* KS0108 requires 450 ns, use 200 here */
 | |
| 	u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);  /* expect 250 here */
 | |
| 	u8x8_gpio_call(u8x8, enable_pin, 0);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       /* disable chipselect */
 | |
|       u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);    
 | |
|       /* ensure that the enable signals are low */
 | |
|       u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_E, 0);
 | |
|       u8x8_gpio_call(u8x8, U8X8_MSG_GPIO_CS, 0);
 | |
|       enable_pin = U8X8_MSG_GPIO_E;
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       u8x8_gpio_SetDC(u8x8, arg_int);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       /* cs lines are not supported for the SED1520/SBN1661 */
 | |
|       /* instead, this will select the E1 or E2 line */ 
 | |
|       enable_pin = U8X8_MSG_GPIO_E;
 | |
|       if ( arg_int != 0 )
 | |
| 	enable_pin = U8X8_MSG_GPIO_CS;
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| 
 | |
| /*
 | |
|   software i2c,
 | |
|   ignores ACK response (which is anyway not provided by some displays)
 | |
|   also does not allow reading from the device
 | |
| */
 | |
| static void i2c_delay(u8x8_t *u8x8) U8X8_NOINLINE;
 | |
| static void i2c_delay(u8x8_t *u8x8)
 | |
| {
 | |
|   //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_10MICRO, u8x8->display_info->i2c_bus_clock_100kHz);
 | |
|   u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_I2C, u8x8->display_info->i2c_bus_clock_100kHz);
 | |
| }
 | |
| 
 | |
| static void i2c_init(u8x8_t *u8x8)
 | |
| {
 | |
|   u8x8_gpio_SetI2CClock(u8x8, 1);
 | |
|   u8x8_gpio_SetI2CData(u8x8, 1);
 | |
|   
 | |
|   i2c_delay(u8x8);
 | |
| }
 | |
| 
 | |
| /* actually, the scl line is not observed, so this procedure does not return a value */
 | |
| 
 | |
| static void i2c_read_scl_and_delay(u8x8_t *u8x8)
 | |
| {
 | |
|   /* set as input (line will be high) */
 | |
|   u8x8_gpio_SetI2CClock(u8x8, 1);
 | |
| 
 | |
|   i2c_delay(u8x8);
 | |
| }
 | |
| 
 | |
| static void i2c_clear_scl(u8x8_t *u8x8)
 | |
| {
 | |
|   u8x8_gpio_SetI2CClock(u8x8, 0);
 | |
| }
 | |
| 
 | |
| static void i2c_read_sda(u8x8_t *u8x8)
 | |
| {
 | |
|   /* set as input (line will be high) */
 | |
|   u8x8_gpio_SetI2CData(u8x8, 1);
 | |
| }
 | |
| 
 | |
| static void i2c_clear_sda(u8x8_t *u8x8)
 | |
| {
 | |
|   /* set open collector and drive low */
 | |
|   u8x8_gpio_SetI2CData(u8x8, 0);
 | |
| }
 | |
| 
 | |
| static void i2c_start(u8x8_t *u8x8)
 | |
| {
 | |
|   if ( u8x8->i2c_started != 0 )
 | |
|   {
 | |
|     /* if already started: do restart */
 | |
|     i2c_read_sda(u8x8);     /* SDA = 1 */
 | |
|     i2c_delay(u8x8);
 | |
|     i2c_read_scl_and_delay(u8x8);
 | |
|   }
 | |
|   i2c_read_sda(u8x8);
 | |
|   /* send the start condition, both lines go from 1 to 0 */
 | |
|   i2c_clear_sda(u8x8);
 | |
|   i2c_delay(u8x8);
 | |
|   i2c_clear_scl(u8x8);
 | |
|   u8x8->i2c_started = 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void i2c_stop(u8x8_t *u8x8)
 | |
| {
 | |
|   /* set SDA to 0 */
 | |
|   i2c_clear_sda(u8x8);  
 | |
|   i2c_delay(u8x8);
 | |
|  
 | |
|   /* now release all lines */
 | |
|   i2c_read_scl_and_delay(u8x8);
 | |
|  
 | |
|   /* set SDA to 1 */
 | |
|   i2c_read_sda(u8x8);
 | |
|   i2c_delay(u8x8);
 | |
|   u8x8->i2c_started = 0;
 | |
| }
 | |
| 
 | |
| static void i2c_write_bit(u8x8_t *u8x8, uint8_t val)
 | |
| {
 | |
|   if (val)
 | |
|     i2c_read_sda(u8x8);
 | |
|   else
 | |
|     i2c_clear_sda(u8x8);
 | |
|  
 | |
|   i2c_delay(u8x8);
 | |
|   i2c_read_scl_and_delay(u8x8);
 | |
|   i2c_clear_scl(u8x8);
 | |
| }
 | |
| 
 | |
| static void i2c_read_bit(u8x8_t *u8x8)
 | |
| {
 | |
|   //uint8_t val;
 | |
|   /* do not drive SDA */
 | |
|   i2c_read_sda(u8x8);
 | |
|   i2c_delay(u8x8);
 | |
|   i2c_read_scl_and_delay(u8x8);
 | |
|   i2c_read_sda(u8x8);
 | |
|   i2c_delay(u8x8);
 | |
|   i2c_clear_scl(u8x8);
 | |
|   //return val;
 | |
| }
 | |
| 
 | |
| static void i2c_write_byte(u8x8_t *u8x8, uint8_t b)
 | |
| {
 | |
|   i2c_write_bit(u8x8, b & 128);
 | |
|   i2c_write_bit(u8x8, b & 64);
 | |
|   i2c_write_bit(u8x8, b & 32);
 | |
|   i2c_write_bit(u8x8, b & 16);
 | |
|   i2c_write_bit(u8x8, b & 8);
 | |
|   i2c_write_bit(u8x8, b & 4);
 | |
|   i2c_write_bit(u8x8, b & 2);
 | |
|   i2c_write_bit(u8x8, b & 1);
 | |
|     
 | |
|   /* read ack from client */
 | |
|   /* 0: ack was given by client */
 | |
|   /* 1: nothing happend during ack cycle */  
 | |
|   i2c_read_bit(u8x8);
 | |
| }
 | |
| 
 | |
| uint8_t u8x8_byte_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   uint8_t *data;
 | |
| 
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;
 | |
|     
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	i2c_write_byte(u8x8, *data);
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
|       }
 | |
|       
 | |
|       break;
 | |
|       
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       i2c_init(u8x8);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       i2c_start(u8x8);
 | |
|       i2c_write_byte(u8x8, u8x8_GetI2CAddress(u8x8));
 | |
|       //i2c_write_byte(u8x8, 0x078);
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       i2c_stop(u8x8);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /*=========================================*/
 | |
| 
 | |
| /* alternative i2c byte procedure */
 | |
| #ifdef ALTERNATIVE_I2C_BYTE_PROCEDURE
 | |
| 
 | |
| 
 | |
| void i2c_transfer(u8x8_t *u8x8, uint8_t adr, uint8_t cnt, uint8_t *data)
 | |
| {
 | |
|   uint8_t i;
 | |
|   i2c_start(u8x8);
 | |
|   i2c_write_byte(u8x8, adr);
 | |
|   for( i = 0; i < cnt; i++ )
 | |
|     i2c_write_byte(u8x8, data[i]);
 | |
|   i2c_stop(u8x8);  
 | |
| }
 | |
| 
 | |
| 
 | |
| uint8_t u8x8_byte_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 | |
| {
 | |
|   static uint8_t buffer[32];		/* u8g2/u8x8 will never send more than 32 bytes */
 | |
|   static uint8_t buf_idx;
 | |
|   uint8_t *data;
 | |
|  
 | |
|   switch(msg)
 | |
|   {
 | |
|     case U8X8_MSG_BYTE_SEND:
 | |
|       data = (uint8_t *)arg_ptr;      
 | |
|       while( arg_int > 0 )
 | |
|       {
 | |
| 	buffer[buf_idx++] = *data;
 | |
| 	data++;
 | |
| 	arg_int--;
 | |
|       }      
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_INIT:
 | |
|       i2c_init(u8x8);			/* init i2c communication */
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_SET_DC:
 | |
|       /* ignored for i2c */
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_START_TRANSFER:
 | |
|       buf_idx = 0;
 | |
|       break;
 | |
|     case U8X8_MSG_BYTE_END_TRANSFER:
 | |
|       i2c_transfer(u8x8, u8x8_GetI2CAddress(u8x8), buf_idx, buffer);
 | |
|       break;
 | |
|     default:
 | |
|       return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| #endif
 |