Я разрабатываю приложение в Atmel Studio 6, используя xMega32a4u. Я использую библиотеки TWI, предоставленные Atmel. По большей части все идет хорошо.
Вот моя проблема: чтобы обновить OLED-дисплей, который я использую (контроллер SSD1306, 128x32), все содержимое оперативной памяти дисплея должно быть записано сразу после команды I2C START, адреса подчиненного устройства и байта управления, чтобы дисплей знал ввести данные в ОЗУ дисплея. Если байт управления не предшествует непосредственно пакету ОЗУ дисплея, ничего не работает.
Я использую логический анализатор Saleae, чтобы убедиться, что шина работает так, как должна.
Вот функция, которую я использую для записи дисплея:
void OLED_buffer(){ // Used to write contents of display buffer to OLED
uint8_t data_array[513];
data_array[0] = SSD1306_DATA_BYTE;
for (int i=0;i<512;++i){
data_array[i+1] = buffer[i];
}
OLED_command(SSD1306_SETLOWCOLUMN | 0x00);
OLED_command(SSD1306_SETHIGHCOLUMN | 0x00);
OLED_command(SSD1306_SETSTARTLINE | 0x00);
twi_package_t buffer_send = {
.chip = OLED_BUS_ADDRESS,
.buffer = data_array,
.length = 513
};
twi_master_write(&TWIC, &buffer_send);
}
Ясно, что это очень неэффективно, поскольку каждый вызов этой функции воссоздает весь массив «buffer» в новый массив «data_array», по одному элементу за раз. Смысл этого в том, чтобы вставить контрольный байт (SSD1306_DATA_BYTE = 0x40) в массив, чтобы весь «пакет» отправлялся сразу, а контрольный байт находился в нужном месте. Я мог бы сделать исходный «буферный» массив на один элемент больше и добавить управляющий байт в качестве первого элемента, чтобы пропустить этот процесс, но это сделает размер 513, а не 512, и может испортить некоторые текстовые / графические функции, которые манипулируют этим. массив и зависит от его правильного размера.
Теперь я подумал, что могу написать такой код:
void OLED_buffer(){ // Used to write contents of display buffer to OLED
uint8_t data_byte = SSD1306_DATA_BYTE;
OLED_command(SSD1306_SETLOWCOLUMN | 0x00);
OLED_command(SSD1306_SETHIGHCOLUMN | 0x00);
OLED_command(SSD1306_SETSTARTLINE | 0x00);
twi_package_t data_control_byte = {
.chip = OLED_BUS_ADDRESS,
.buffer = data_byte,
.length = 1
};
twi_master_write(&TWIC, &data_control_byte);
twi_package_t buffer_send = {
.chip = OLED_BUS_ADDRESS,
.buffer = buffer,
.length = 512
};
twi_master_write(&TWIC, &buffer_send);
}
/*
Это не работает. Первая команда twi_master_write отправляет СТАРТ, адрес, управление, СТОП. Затем следующая такая команда отправляет СТАРТ, адрес, буфер данных, СТОП. Поскольку в последней транзакции отсутствует контрольный байт, это не работает. Все, что мне нужно, это вставить байт 0x40 между байтом адреса и массивом буферов, когда он отправляется по шине I2C. twi_master_write - это функция, которая предоставляется в библиотеках Atmel TWI. Я пытался изучить библиотеки, чтобы понять их внутреннюю работу, но не могу понять этого.
Конечно, вместо того, чтобы выяснять, как воссоздать функцию twi_write, чтобы она работала так, как мне нужно, есть более простой способ добавить этот предыдущий управляющий байт? В идеале такой, который не был бы так расточителен по тактовым циклам, как мой первый пример кода? На самом деле дисплей по-прежнему обновляется очень быстро, более чем достаточно для моих нужд, но это не меняет того факта, что это неэффективный код.
Я ценю любой совет, который вы можете дать. Заранее спасибо!