 389ff92cc1
			
		
	
	
		389ff92cc1
		
			
		
	
	
	
	
		
			
			* Makefile, Scripts: new linter * About: remove ID from IC * Firmware: remove double define for DIVC/DIVR * Scripts: check folder names too. Docker: replace syntax check with make lint. * Reformat Sources and Migrate to new file naming convention * Docker: symlink clang-format-12 to clang-format * Add coding style guide
		
			
				
	
	
		
			624 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			624 lines
		
	
	
		
			19 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
 |