Портирование «дальнего» доступа к флэш-памяти с Arduino Mega на Due

У меня есть проект, работающий на Arduino Mega 2560, который занимает почти весь доступный объем флэш-памяти (https://github.com/fredlcore/bsb_lan/blob/master/BSB_lan.ino). Из-за этого я планирую перенести проект на Arduino Due.

Основная моя проблема на данный момент - портировать те функции, которые обращаются к flash памяти в "дальней" области памяти (>64k) для которых с одной стороны предусмотрены различные _PF функции (типа strncpy_PF), а с другой стороны доступен фиктивный тип «указателя» uint_farptr_t (на самом деле это uint32_t).

Сейчас у меня две проблемы:

  1. Несмотря на то, что функции _PF имеют специальные определения для Due, которые в "нормальных" условиях должны работать без изменений в коде, они предполагают различные типы переменных. Например, strncpy_PF принимает uint_farptr_t (т.е. uint32_t) в качестве аргумента для src на Mega, он ожидает const char * на Due. Таким образом, компиляция приводит к большому количеству ошибок.

  2. Чтобы Mega могла получить доступ к массивам символов (16-битные в Mega) выше 128 КБ, мне нужен довольно грязный обходной путь (см. функцию calc_enum_offset() в приведенном выше коде). В основном мне нужно взять адрес памяти 16-битного указателя символов и выполнить некоторые вычисления, чтобы получить окончательный адрес, с которого я читаю строки. В Mega я могу выполнять эти вычисления на основе uint_farptr_t, а затем читать из рассчитанного адреса памяти, например, с помощью pgm_read_byte_far(). Однако в Due pgm_read_byte_far(addr) преобразуется в (*(const unsigned char *)(addr)). Опять же, тип uint32_t здесь не подходит.

Есть ли у вас какие-либо предложения о том, как мне решить эти проблемы с наименьшим объемом кода?

, 👍0

Обсуждение

тип указателя на Due имеет 32 бита, поэтому const char* равен uint32_t. Я бы использовал ifdefs, чтобы пропустить использование дальних вариантов, @Juraj

@Juraj: Хм, uint_farptr_t на Mega также является uint32_t, и я использую его для доступа к ячейкам памяти строк во флэш-памяти (которые я вычисляю на основе (усеченного) 16-битного указателя символов. Есть ли способ получить доступ Ячейки памяти const char* выводятся на Due аналогичным образом, например, получая адрес памяти const char*, выполняя некоторые вычисления по этому адресу и читая (например, символ) из полученной ячейки памяти? быть не/менее эффективным, но если бы это позволило мне поддерживать работу большей части моего кода на двух архитектурах, это было бы то, что я ищу., @fredlcore


1 ответ


Лучший ответ:

1

Due, будучи ARM, представляет собой архитектуру фон Неймана. Это означает, что в нем нет понятия «программная память», «ближний» или «дальний» указатели и т. д. Нет вариантов функций _P или _PF, но ядро Arduino для удобства предоставляет простые заглушки.

Вместо этого любой доступ к флэш-памяти представляет собой просто доступ к памяти с использованием const.

Лучшее, что вы можете сделать, это использовать макросы препроцессора для выбора между кодом AVR и ARM:

#if defined(__AVR__)
    strncpy_PF(buffer, enumstr+c, sizeof(buffer));
    buffer[sizeof(buffer)-1] = 0;
    outBufLen+=sprintf(outBuf+outBufLen,"%d - %s",val,buffer);
#else
    outBufLen += sprintf(outBuf + oufBufLen, "%d - %s", val, cmdtbl[i].enumstr);
#endif

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

,

Спасибо за полезный пример, и да, переписать, безусловно, было бы лучшим вариантом, но, учитывая тот факт, что текущая пользовательская база с Arduino Mega составляет несколько сотен пользователей, которым я все же хотел бы предоставить исправления ошибок без необходимости поддерживать два кодовые базы, это не вариант. Применение вашего примера в различных формах ко всем более чем 100 вхождениям функций ...far... сделает код полным беспорядком. Так что я все еще надеюсь, есть ли способ решить это на уровне вызываемых функций, а затем обрабатываться там на основе соответствующей архитектуры?, @fredlcore

Вы можете поместить все в функции-оболочки, а затем запросить эти функции для каждой платформы. Переместите разные платформы в разные включаемые файлы, а затем включайте только те, которые соответствуют текущей архитектуре., @Majenko

Это звучит как осуществимый план, спасибо!, @fredlcore