Добавление дополнительных данных в PROGMEM прерывает передачу SPI на Arduino Mega 2560 - PullRequest
1 голос
/ 09 января 2020

Я работаю над небольшим проектом (или так я думал), включающим Arduino Mega (2560) и дисплей Waveshare ePaper.

У меня все работает нормально с библиотекой ( epd7in5 ) и я добавил два изображения в PROGMEM. Но как только я добавляю третье изображение (и, следовательно, третью запись в PROGMEM), экран ePaper почему-то больше не запускается. Добавление некоторой отладки в библиотеку показывает, что код застревает на указанном c SPI.transfer().

РЕДАКТИРОВАТЬ: Теория Возможно ли, что SPI не совместим, когда слишком много данных во фла sh? Я прочитал об этом, что 64 КБ это максимум. Я немного выше этого с двумя изображениями, но значительно с тремя. Может быть, это нарушает SPI? И если так: могу ли я это исправить?

Я добавил приведенный ниже код и определенную c часть библиотеки, где происходит сбой SPI.transfer().

Main. cpp

Удаление кода, связанного с dummy3, гарантирует, что массив dummy3 не скомпилируется. Только используя dummy1 и dummy2 все работает нормально. Добавление dummy3 и программа застревает на epd.Init().

#include <SPI.h>
#include <epd7in5.h>
#include "imagedata.h"

Epd epd;

void debug(String);

void setup() {
  Serial.begin(9600);
  debug("Serial begin");

  if (epd.Init() != 0) {
    debug("INIT FAILED!");
    return;
  }

  debug("Changing image");
  epd.DisplayFrame(dummy1);  //DisplayFrame by default includes WaitUntilIdle.
  debug("dummy1 on ePaper");
  delay(1000);
  debug("Changing image");
  epd.DisplayFrame(dummy2);
  debug("dummy2 on ePaper");
  delay(1000);
  debug("Changing image");
  epd.DisplayFrame(dummy3);
  debug("dummy2 on ePaper");
  epd.SendCommand(POWER_OFF); 
  debug("POWER_OFF");
}

void loop() {
}

void debug(String message) {
  Serial.print(millis());
  Serial.print("\t");
  Serial.println(message);
}

imagedata. cpp

Я удалил фактические данные изображения, так как они МНОГО. Два изображения приводят к общему объему sh 67326 байт (около 26% от общего объема sh mem из 2560). Три изображения дают общий размер sh 98052 байта (около 38% от общего объема sh mem из 2560). Заголовочный файл содержит просто объявления.

#include "imagedata.h"
#include <avr/pgmspace.h>

const unsigned char dummy1[30726] PROGMEM = {...data...};
const unsigned char dummy2[30726] PROGMEM = {...data...};
const unsigned char dummy3[30726] PROGMEM = {...data...};

epd7in5. cpp

Я добавил функцию отладки. SendData также включен и использует отладку.

void Epd::debug(String message) {
  Serial.print(millis());
  Serial.print("\t");
  Serial.print("EPD");
  Serial.print("\t");
  Serial.println(message);
}

int Epd::Init(void) {
  if (IfInit() != 0) {
    return -1;
  }

  debug("Resetting");
  Reset();

  debug("SendCommand(POWER_SETTING);");
  SendCommand(POWER_SETTING);
  debug("SendData(0x37);");
  SendData(0x37);
  debug("SendData(0x00);");
  SendData(0x00);

  debug("SendCommand(PANEL_SETTING);");
  SendCommand(PANEL_SETTING);
  SendData(0xCF);
  SendData(0x08);

  SendCommand(BOOSTER_SOFT_START);
  SendData(0xc7);
  SendData(0xcc);
  SendData(0x28);

  SendCommand(POWER_ON);
  WaitUntilIdle();

  SendCommand(PLL_CONTROL);
  SendData(0x3c);

  SendCommand(TEMPERATURE_CALIBRATION);
  SendData(0x00);

  SendCommand(VCOM_AND_DATA_INTERVAL_SETTING);
  SendData(0x77);

  SendCommand(TCON_SETTING);
  SendData(0x22);

  SendCommand(TCON_RESOLUTION);
  SendData(0x02);  //source 640
  SendData(0x80);
  SendData(0x01);  //gate 384
  SendData(0x80);

  SendCommand(VCM_DC_SETTING);
  SendData(0x1E);  //decide by LUT file

  SendCommand(0xe5);  //FLASH MODE
  SendData(0x03);

  return 0;
}

void Epd::SendData(unsigned char data) {
  debug("DigitalWrite(dc_pin, HIGH);");
  DigitalWrite(dc_pin, HIGH);
  debug("SpiTransfer(data);");
  SpiTransfer(data);
}

epdif. cpp

Эта часть передачи SPI не продолжается.

void EpdIf::SpiTransfer(unsigned char data) {
    digitalWrite(CS_PIN, LOW);
    SPI.transfer(data);
    digitalWrite(CS_PIN, HIGH);
}

Последовательная печать проекта выглядит следующим образом ...

0   Serial begin
0   EPD Resetting
400 EPD SendCommand(POWER_SETTING);
400 EPD SendData(0x37);
400 EPD DigitalWrite(dc_pin, HIGH);
435 EPD SpiTransfer(data);

Итак, как только он запускается SpiTransfer, код просто перестает работать. Кажется, это бесконечно l oop в SPI.transfer();, но я не знаю точно, как это могло бы произойти. Я не понимаю, как PROGMEM может помешать передаче, и у меня достаточно фл sh памяти осталось ...

Что может быть решением для этого? Это проблема в SPI, что мне нужно изменить? Или мне нужно хранить мои данные по-другому в PROGMEM? Я немного растерялся.

Заранее благодарю за помощь, очень признателен.

1 Ответ

0 голосов
/ 09 января 2020

Ваша проблема не с SPI (сама по себе).

Это связано с количеством данных, которые вы имеете в программе и читаете ее. Если вы используете более 64 Кб Progmem, вы сталкиваетесь с 2 различными наборами проблем:

  1. Чтение данных надежным способом

Чтение программа должна использовать макросы pgm_read_xxx_far для любого адреса после 65536. Epd::DisplayFrame использует pgm_read_byte(&frame_buffer[i]);, поэтому у вас есть проблема на уровне библиотеки. Я не знаком с этой библиотекой, поэтому я не уверен, есть ли альтернативная функция, которую вы можете вызвать, и предоставить буфер самостоятельно, прочитав его из PROGMEM с помощью pgm_read_byte_far. Это легкая часть проблемы

Передача указанных данных в PROGMEM в первую очередь

Ядро Arduino и сам компилятор avr предполагают, что все указатели имеют только 16 бит. При помещении данных в PROGMEM они появляются перед ядром arduino и исполняемым кодом в конечном исполняемом файле, который запускает вашу программу.

Надежный способ сделать это правильно - использовать собственный скрипт компоновщика, который уберет ваши данные и разместит их после всего исполняемого кода. Это было бы сложно, и я боюсь, что не могу дать никакой информации о том, как выполнить sh.

В качестве альтернативы, вы можете попробовать использовать _attribute__((section(".fini2"))), чтобы использовать раздел .fini2. Некоторые люди делали это раньше, и это работало на них.

Вы бы использовали его так:

const unsigned char __attribute__((section(".fini2"))) dummy1[30726] = {...data...};

Последняя альтернатива - вообще не использовать PROGMEM и иметь какое-то внешнее хранилище, которое вы используете для своих данных (например, некоторые SD Card). Скорее всего, это был бы самый простой способ решения этой проблемы.

Источник : Эта превосходная тема и замечательное понимание westfw на форумах arduino: https://forum.arduino.cc/index.php?topic=485507.0

...