Зависание шины I2c при работе с драйвером SSD1306

Здрасти! Уже почти неделю пытаюсь подружить АTMega328p c драйвером OLED дисплея SSD1306. После отправки адреса и бита записи получаю в ответ ack, после отправляю байт команды и шина будто зависает ни ack ни nack. Осцилографа в наличии нет, так что проверить состояние линий шины в реальных условиях не могу, все операции провожу в протеусе, так что не совсем понимаю моя ошибка или ошибка симуляции, но с другими устройствами с i2c подобных проблем не возникало . Может кто сможет ткнуть носом на ошибку, заранее спасибо.

Мой код:

                                 .include			"m328PBdef.inc"

				.def				buff		= r16
				.def				message	= r17
				.def				iter		= r18

				.equ				adressW = 0b01111000

				.cseg

				.org				0x0000
				jmp				restart

				.org				0x001A
				jmp				tim1_ovf_isr

				.org				0x0030
				jmp				twi_isr

restart:		ldi				buff,   high(RAMEND)
				out				SPH,    buff
				ldi				buff,   low(RAMEND)
				out				SPL,    buff
;				 twi init
				ldi				buff,   0b1100
				sts				TWBR0,  buff

				ldi				buff,   0b0
				sts				TWSR0,  buff
;				 timer\counter init
				ldi				buff,   0b100
				sts				TCCR1B, buff

				ldi				buff,   0b1
				sts				TIMSK1, buff
;				global interrupt enable
				sei
;				main routine

main:			
				jmp				main

;				timer 1 - 16bit overflow isr

tim1_ovf_isr:	ldi				buff,   0b10100101
				sts				TWCR0,  buff

				ldi				buff, 0b0
				sts				TCCR1B, buff

				ldi				buff,   0b0
				sts				TIMSK1, buff

				reti
;				twi isr
twi_isr:		lds				buff, TWSR0
				andi				buff, 0b11111000

				cpi				buff, 0x08
				breq				twi_start

				cpi				buff, 0x18
				breq				twi_slaw_ack

				cpi				buff, 0x28
				breq				twi_data_ack
				
				reti
;
twi_start:		ldi				buff, adressW
				sts				TWDR0, buff

				ldi				buff, 0b10000101
				sts				TWCR0, buff

				reti
;
;
twi_slaw_ack:	ldi				buff, 0b10000000
				sts				TWDR0, buff

				ldi				buff, 0b10000101
				sts				TWCR0, buff

				reti
;
;
twi_data_ack:	ldi				buff, 0xA5
				sts				TWDR0, buff

				ldi				buff, 0b10000101
				sts				TWCR0, buff
				reti

Без лог анализатора концы найти почти нереально.

1 лайк

Я как-то тоже потерял, к счастью только сутки, потом выкинул протеус и в реале на железе отладил два устройства соединённых по i2c.

1 лайк

Именно с этой моделью не работал в Proteus, но работал с UG-2864HSWEG01 с ней всё более менее нормально отрабатывает.
Если что - есть проекты готовые для Proteus…
Писать на ассемблере с использованием магических чисел - это уже перебор !!!
После адреса идёт байт 0x00 для команд или 0x40 для данных картинки - что за 0x80 у вас мне не понятно …

Может мой код чем поможет...

Это запись в MCP4725 без прерываний.

.CSEG

.ORG		$0
	RJMP	Start

.ORG		INT_VECTORS_SIZE

Start:
	LDI	R16,Low(RAMEND)
	OUT	SPL,R16
	LDI	R16,High(RAMEND)
	OUT	SPH,R16
	SBI	DDRD,DDD5
	SBI	DDRD,DDD6
	LDI	R16,0
	OUT	TCNT0,R16
	LDI	R16,7
	OUT	OCR0A,R16
	OUT	OCR0B,R16
	LDI	R16,0B01010010
	OUT	TCCR0A,R16
	LDI	R16,0B11000001
	OUT	TCCR0B,R16
	CLR	R27
	LDI	R26,TWCR
	CLR	R29
	LDI	R28,TWDR
	LDI	R18,0
	STS	TWBR,R18
Loop:
	LDI	R18,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
	ST	X,R18
	LDI	R17,0xC0
	LDI	R18,(1<<TWINT)|(1<<TWEN)
wait1:
	LD	R16,X
	SBRS R16,TWINT
	RJMP wait1
	ST	Y,R17
	ST	X,R18
	LDI	R17,0x07
wait2:
	LD	R16,X
	SBRS R16,TWINT
	RJMP wait2
	ST	Y,R17
	ST	X,R18
	LDI	R17,0xFF
wait3:
	LD	R16,X
	SBRS R16,TWINT
	RJMP wait3
	ST	Y,R17
	ST	X,R18
	LDI	R18,(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)
wait4:
	LD	R16,X
	SBRS R16,TWINT
	RJMP wait4
	ST	X,R18
	RJMP	Loop

Это работа с ssd1306 через прерывания.
sketch.ino - Wokwi Arduino and ESP32 Simulator

/*
 * Copyright (C) 2022, Andrei Egorov
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define SSD1306_addr 0x3C

static const uint8_t PROGMEM init_bytes[]={SSD1306_addr<<1,0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8,
																																0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF};

static const uint8_t PROGMEM screen[]={
0x00, 0x7c, 0x12, 0x12, 0x12, 0x7c, 0x00, 0x7e, 0x12, 0x12, 0x12, 0x6c, 0x00, 0x7e, 0x42, 0x42, 
0x42, 0x3c, 0x00, 0x3e, 0x40, 0x40, 0x40, 0x3e, 0x00, 0x7a, 0x00, 0x7e, 0x08, 0x10, 0x20, 0x7e, 
0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x40, 0x00, 0x7e, 0x12, 0x12, 0x12, 0x6c, 0x00, 0x3e, 
0x40, 0x40, 0x40, 0x3e, 0x00,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33
};

volatile int buff_size=sizeof(init_bytes);
const uint8_t *buff_ptr=init_bytes;

void setup() {
	digitalWrite(SDA,1);
	digitalWrite(SCL,1);
	TWBR=26;     //TWBR=26; calculated for 24 FPS (TWBR=1; for 80 FPS )
	TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE);
	while (buff_size>=0);
	delay(1);
  TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	while (TWCR&(1<<TWSTO));
	TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while (!(TWCR&(1<<TWINT)));
	TWDR=SSD1306_addr<<1;
	TWCR=(1<<TWINT)|(1<<TWEN);
	while (!(TWCR&(1<<TWINT)));
	TWDR=0x40;
	TWCR=(1<<TWINT)|(1<<TWEN);
}

void loop() {
	buff_size=sizeof(screen);
	buff_ptr=screen;
	TWCR|=(1<<TWIE);
	while (buff_size!=0) {
		//any code without CLI()
	};
}

ISR (TWI_vect,ISR_NAKED) {
	if (buff_size>=0) {
		TWDR=pgm_read_byte(buff_ptr++);
		TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWIE);
		buff_size--;
	}
	reti();
}
1 лайк

Спасибо вам за пример. По поводу магических чисел это мои попытки перебора байта идущего после sla+w. Может у меня даташит не правильный или я глупий(что вероятнее всего) но вот что написано в даташите:

вот в строке касающейся C0 бита, сделал вывод что для отправки команды нужно написать 0b10 000000… впрочем перепробовал все комбинации и ничего не изменилось. С модулем UG-2864HSWEG01 та же история …

Весь код у вас типа ldi buff, 0b10100101. Везде неясные константы - “магические числа”.

SSD1306_addr<<1, 0x00 ,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8,0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF

Тут все байты подряд что должны быть переданы на этапе инициализации. После этого дисплей должен включится с мусором на экране.
D/C это 7ой бит ! То есть либо 0x00 либо 0x40.
Он ваши 0x80 не понимает и всё !

замените на
twi_slaw_ack: ldi buff, 0b00000000`
И сделайте на первом этапе без прерываний …

Получилось, спасибо… правда не совсем понял где вы нашли эти команды для инициализации, у меня в даташите этого не описано… И помимо этого проблема была с протеусом, на железе данный код работает дисплей включился(выводит мусор из памяти) , а в протеусе шина i2c зависает, повторил то же с интераптами , полёт нормальный. Спасибо за помощь!

Спойлер

				.include			"m328PBdef.inc"

				.equ				adrr = 0x78

;					--- code segment ---				;
				.cseg
				.org				0x0000
				jmp				restart

				.org				0x0020
				jmp				tim0_ovf
				
				.org				0x0030
				jmp				twi_isr
				
restart:			ldi				r16, high(RAMEND)
				out				SPH, r16
				ldi				r16, low(RAMEND)
				out				SPL, r16

				ldi				r16, 0x0C
				sts				TWBR0, r16
				ldi				r16, 0
				sts				TWSR0, r16

				rcall			ssd1306init

				
main:			

				jmp				main


;					--- sub-routine ---				;
ssd1306init:		push				r30
				push				r31
				push				r16
				push				r17

				ldi				r17, 0			;	iterator from 0 to 26
				ldi				r16, 0b10100100	
				sts				TWCR0, r16

loop:			cpi				r17, 0x1A			
				breq				init_exit
wait_for_int:		lds				r16, TWCR0
				sbrs				r16, 7			;	check for twint flag
				jmp				wait_for_int

				ldi				ZL, low(init*2)
				ldi				ZH, high(init*2)
				add				ZL, r17
				lpm				r16, Z
				sts				TWDR0, r16
				
				ldi				r16, 0b10000100
				sts				TWCR0, r16
				inc				r17
				jmp				loop

init_exit:		ldi				r16, 0b10010100
				sts				TWCR0, r16

				pop				r17
				pop				r16
				pop				r31
				pop				r30
				ret

;					--- const values ---			;

init:			.db				adrr,0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xCB,0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF
	
;					--- isr ---					;


tim0_ovf:			reti

twi_isr:			reti

может оно и ни к чему НО!

.include			"m328PBdef.inc"

немножно не то, что:

.include			"m328Pdef.inc"
или
.include			"m328def.inc"
1 лайк

В разных библиотеках обычно команды отправляют по одной, но данный контроллер также принимает команды пачкой !
Для экранов 128х32 и 128х64 код инициализации немного отличается.
Судя по листингу вы скопировали код из листинга после работы компилятора C++ :slight_smile:
На ассемблере можно написать короче и красивее.

вот зачем ты меня разочаровываешь, я то думал что разработчики компилятора довели его до совершенства )))

Блажен, … кто верует !

Немного поковырялся.
С кодом, использующим аппаратные средства TWI - i2c debugger ругается на ACK.
Сами эти ACK с каким то непонятным уровнем - где то 3.3 вольта (вместо 0).
Но сама модель дисплея отрабатывает и выводит картинки.
На стороне МК- если читать статусы TWI, то идут ошибки ACK. Если не читать ошибки, то всё передаётся и отображается …
proteus

Аппаратный TWI
#define	F_CPU 16000000
#define	F_TWI 100000
#define oled_address  0x3C<<1

.CSEG

.ORG	0x0000
  LDI	R16,Low(RAMEND)
  OUT	SPL,R16
  LDI	R16,High(RAMEND)
  OUT	SPH,R16
  LDI R28,TWBR
  CLR R29
  LDI R16,(F_CPU/F_TWI-16)/2
  ST  Y,R16
  STD Y+TWSR-TWBR,R29
  LDI	ZL,low(oled_init_bytes*2)
  LDI	ZH,high(oled_init_bytes*2)
  LDI	R26,((arduino-oled_init_bytes)*2-1)
  CLR	R27
  SEI
  LDI R17,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)
  STD Y+TWCR-TWBR,R17
  LDI R17,(1<<TWINT)|(1<<TWEN)|(1<<TWIE)
loop1:
  SBRS  R27,7
  RJMP  loop1
  LDI R17,(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)
  STD Y+TWCR-TWBR,R17
loop2:
  SBIC PINC,PINC4
  RJMP  loop2
loop3:
  SBIS PINC,PINC4
  RJMP  loop3 
  LDI	ZL,low(arduino*2)
  LDI	ZH,high(arduino*2)
  LDI	R27,0
  LDI	R26,131
  LDI R17,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)
  STD Y+TWCR-TWBR,R17
  LDI R17,(1<<TWINT)|(1<<TWEN)|(1<<TWIE)
  SBI DDRD,PD5
loop4:
  SBI PIND,PD5
  SBRS  R27,7
  RJMP  loop4
  LDI	ZL,low(arduino*2+2)
  LDI	ZH,high(arduino*2+2)
  LDI	R27,0
  LDI	R26,129
  LDI R17,(1<<TWEN)|(1<<TWIE)
  STD Y+TWCR-TWBR,R17
  RJMP  loop4

.ORG	TWIaddr
  IN  R16,SREG
  PUSH  R16
  SBIW  R26,1
  BRCC  TWInext
  LDI R17,(1<<TWEN)
  RJMP  TWInext1
TWInext:
  LDI R17,(1<<TWINT)|(1<<TWEN)|(1<<TWIE)
  LPM R16,Z+
  STD Y+TWDR-TWBR,R16
TWInext1:
  STD Y+TWCR-TWBR,R17
  POP R16
  OUT SREG,R16
  RETI

oled_init_bytes:
  .db oled_address,0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8
  .db              0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF,		0x00
arduino:
  .db oled_address,0x40
  .db 0x00,0x7c,0x12,0x12,0x12,0x7c,0x00,0x7e,0x12,0x12,0x12,0x6c,0x00,0x7e,0x42,0x42
  .db 0x42,0x3c,0x00,0x3e,0x40,0x40,0x40,0x3e,0x00,0x7a,0x00,0x7e,0x08,0x10,0x20,0x7e
  .db 0x00,0x3c,0x42,0x42,0x42,0x3c,0x00,0x40,0x00,0x7e,0x12,0x12,0x12,0x6c,0x00,0x3e
  .db 0x40,0x40,0x40,0x3e,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0x55,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  .db 0xFF,0x00


В эту же модель вставляю код программного I2C. Все ACK на месте и с правильным уровнем сигнала.

Программный I2C
.equ		oled_address 	=0x3C<<1
.equ		SCLPORT		=PORTC
.equ		SCLPIN		=PORTC5
.equ		SDAPORT		=PORTC
.equ		SDAPIN		=PORTC4

.CSEG

.ORG	0x0000
	RJMP	Start

oled_init_bytes:
	.db oled_address,0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8
	.db              0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF,		0x00
impreza:

;------------------------------
i2c_init:
	CBI	SCLPORT-1,SCLPIN
	CBI	SDAPORT-1,SDAPIN
	CBI	SDAPORT,SDAPIN
	CBI	SCLPORT,SCLPIN
	RET

;------------------------------
i2c_start:
	SBI	SDAPORT-1,SDAPIN
	RET

;------------------------------
i2c_restart:
	CBI	SCLPORT-1,SCLPIN
	CBI	SCLPORT-1,SCLPIN
	SBI	SDAPORT-1,SDAPIN
	RET

;------------------------------
i2c_write:
	LDI	R25,8
i2c_write_loop:
	SBI	SCLPORT-1,SCLPIN
	SBRC	R24,7
	CBI	SDAPORT-1,SDAPIN
	SBRS	R24,7
	SBI	SDAPORT-1,SDAPIN
	ROL	R24
	CBI	SCLPORT-1,SCLPIN
i2c_write_loop1:
	SBIS	SCLPORT-2,SCLPIN
	RJMP	i2c_write_loop1
	NOP
	DEC	R25
	BRNE	i2c_write_loop
	NOP
	SBI	SCLPORT-1,SCLPIN
	CBI	SDAPORT-1,SDAPIN
	CBI	SDAPORT-1,SDAPIN
	CBI	SDAPORT-1,SDAPIN
	CBI	SCLPORT-1,SCLPIN
	CLR	R24
	SBIS	SDAPORT-2,SDAPIN
	INC	R24
	CBI	SCLPORT-1,SCLPIN
	NOP
	SBI	SCLPORT-1,SCLPIN
	RET

;------------------------------
i2c_read:
	LDI	R25,8
	BST	R24,0
i2c_read_loop:
	SBI	SCLPORT-1,SCLPIN
	SBI	SCLPORT-1,SCLPIN
	SBI	SCLPORT-1,SCLPIN
	BLD	R24,0
	LSL	R24
	CBI	SCLPORT-1,SCLPIN
	SET
	SBIS	SDAPORT-2,SDAPIN
	CLT
	DEC	R25
	BRNE	i2c_read_loop
	BLD	R24,0
	SBI	SCLPORT-1,SCLPIN
	ROL	R25
	SBRS	R25,0
	SBI	SDAPORT-1,SDAPIN
	SBRC	R25,0
	CBI	SDAPORT-1,SDAPIN
	CBI	SCLPORT-1,SCLPIN
	CBI	SCLPORT-1,SCLPIN
	CBI	SCLPORT-1,SCLPIN
	CBI	SCLPORT-1,SCLPIN
	SBI	SCLPORT-1,SCLPIN
	CBI	SDAPORT-1,SDAPIN
	RET

;------------------------------
i2c_stop:
	SBI	SDAPORT-1,SDAPIN
	CBI	SCLPORT-1,SCLPIN
	CBI	SCLPORT-1,SCLPIN
	CBI	SDAPORT-1,SDAPIN
	RET

;------------------------------
i2c_write_buff:
	LPM	R24,Z+
	CALL	i2c_write
	SBIW	R26,1
	BRNE	i2c_write_buff
	RET

;------------------------------
i2c_write_zero:
	PUSH	R24
	PUSH R20
i2c_write_zero_loop:
	CLR	R24
	CALL	i2c_write
	DEC	R20
	BRNE	i2c_write_zero_loop
	POP	R20
	POP	R24
	RET

;------------------------------
Start:
	LDI	R16,Low(RAMEND)
	OUT	SPL,R16
	LDI	R16,High(RAMEND)
	OUT	SPH,R16
	LDI	ZL,low(oled_init_bytes*2)
	LDI	ZH,high(oled_init_bytes*2)
	LDI	R26,((impreza-oled_init_bytes)*2-1)
	CLR	R27
	CALL	i2c_init
	CALL	i2c_start
	CALL	i2c_write_buff
	CALL	i2c_stop
	CALL	i2c_start
	LDI	R24,oled_address
	CALL	i2c_write
	LDI	R24,0x40
	CALL	i2c_write
loop:
	LDI	R24,0xAA
	CALL	i2c_write
	LDI	R24,0x55
	CALL	i2c_write
	LDI	R24,0xAA
	CALL	i2c_write
	RJMP	loop

Если в эту же модель добавить MCP4725, то общение с ней любым способом работает абсолютно адекватно !
Кто виноват и что делать пока не ясно.