Редактируемый серийный номер PIC в файле HEX

8

В настоящее время в моей прошивке прописан серийный номер для дизайна, с которым я работаю. Прошивка может прочитать и сообщить серийный номер. Это прекрасно работает для того, что мне нужно. Проблема в том, что каждый новый серийный номер требует от меня изменения кода и перекомпиляции. Это громоздко, когда нужно построить много модулей, возможно, они могут привести к ошибкам, и это плохая практика. Серийные номера даны мне, а аппаратный дизайн выложен камнем, поэтому я не могу добавить какие-либо функции в аппаратное обеспечение для сериализации устройств (EEPROM / Silicon ID Chip / Pull-Ups). Я хотел бы найти серийный номер по фиксированному адресу, скомпилировать код один раз, а затем отредактировать этот адрес в скомпилированном HEX-файле для каждого нового серийного номера. На номер ссылаются в нескольких местах, поэтому в идеале я хочу определить и найти его один раз, затем ссылка на эту «переменную» везде в моем коде. Кто-нибудь знает, как найти постоянные данные в определенном адресуемом месте памяти по моему выбору, используя компилятор C18? Кто-нибудь может предложить лучший способ?

Джоэл Б
источник
1
Около половины PIC18 имеют от 128 байтов до 1K EEPROM, встроенных в них. Я полагаю из вашего вопроса, что ваш PIC18 является одним из 50%, которые не имеют EEPROM?
tcrosley

Ответы:

4

Специально для решения вопроса о привязке переменных к определенным адресам во флэш-памяти на PIC18 с помощью компилятора C18, пожалуйста, обратитесь к разделу «Прагмы» в hlpC18ug.chm в каталоге doc, где установлен компилятор.

Для этого вам нужно определить новый «раздел» в памяти и привязать его к начальному адресу, чтобы

#pragma romdata serial_no_section=0x1700

Это создает новый раздел с именем «serial_no_section», который начинается с адреса 0x1700 во флэш-памяти (программе) (поскольку мы определили «romdata» в #pragma).

Сразу после строки #pragma определите вашу переменную (и) так:

#pragma romdata serial_no_section=0x1700
const rom int mySerialNumber = 0x1234;
#pragma romdata

Теперь у вас есть 0x12 по адресу 0x1700 и 0x34 по адресу 0x1701 в памяти (потому что PIC18 использует модель с прямым порядком байтов). «Const rom» гарантирует, что компилятор знает, что это тип переменной const, и что переменная находится в памяти «rom» и, следовательно, должна быть доступна с помощью инструкций чтения таблиц.

Последний #pragma romdataоператор гарантирует, что любые последующие объявления переменных связаны с разделами памяти по умолчанию, так как компоновщик считает, что подходит, а не следует в разделе "serial_no_section".

Теперь весь код может просто ссылаться на переменную «mySerialNumber», и вы точно знаете, по какому адресу находится серийный номер в памяти.

Редактирование кода HEX может быть немного сложным, так как вам нужно вычислить контрольную сумму для каждой строки, которую вы редактируете. Я работаю над классом C ++ для декодирования и кодирования файлов Intel HEX, что должно сделать это проще, но это еще не закончено. Декодирование файлов работает, кодирование снова еще не реализовано. Проект (если вы заинтересованы) находится здесь https://github.com/codinghead/Intel-HEX-Class

Надеюсь это поможет

Стюарт Кординг
источник
4

Я сделал серийный номер (s / n для краткости) способом, аналогичным тому, что описывает Джоэл. Я использовал PIC18F4620 и компилятор CCS. Расположение s / n во флэш-памяти было принудительно установлено до последних 4 байтов. Поскольку я использовал только 80% Flash, мой компилятор и компоновщик не писал бы исполняемый код в последние 4 байта.

Тогда у меня было 2 альтернативных способа записи s / n в отдельные единицы:

  • Внутрисхемный отладчик CCS (ICD) имеет функцию, которая позволяет манипулировать любым местоположением внутри Flash. Это был полезный хак. В более поздних версиях они удалили это, к сожалению.
  • ПИК имел последовательную ссылку на ПК. S / N был загружен через него. В прошивке была подпрограмма, которая получала з / п и сохраняла его во Flash.

Ответить на комментарий Джоэла

Не знаю насчет C18, но CCS-компилятор поставляется с библиотечными функциями write_program_eeprom(...)и read_program_eeprom(...). Вот как они выглядят при сборке.

.................... write_program_eeprom (i_ADDR, iWord);
EF84: BSF FD0.6
EF86: CLRF FF8
EF88: MOVLW 7F
EF8A: MOVWF FF7
EF8C: MOVLW F0
EF8E: MOVWF FF6
EF90: MOVLB 0
EF92: BRA EF24
EF94: MOVLW F0
EF96: MOVWF FF6
EF98: MOVFF 490, FF5
EF9C: TBLWT * +
EF9E: MOVFF 491, FF5
EFA2: TBLWT *
EFA4: BCF FA6.6
EFA6: BSF FA6.4
EFA8: RCALL EF3C
EFAA: RCALL EF3C
EFAC: CLRF FF8
EFAE: CLRF FF8
.................... iWord = read_program_eeprom (i_ADDR); 
EF60: CLRF FF8
EF62: MOVLW 7F
EF64: MOVWF FF7
EF66: MOVLW F0
EF68: MOVWF FF6
EF6A: TBLRD * +
EF6C: MOVF FF5, W
EF6E: TBLRD *
EF70: MOVFF FF5,03
EF74: CLRF FF8
EF76: MOVLB 4
EF78: MOVWF x90
EF7A: MOVFF 03,491
Ник Алексеев
источник
1
Да, это именно то, что я прошу! Можете ли вы описать, какие атрибуты кода вы использовали, чтобы упаковать ваш S / N в последние несколько байтов флэш-памяти?
Джоэл Б
«У прошивки была подпрограмма, которая получала з / п и сохраняла его во Flash» write_program_eeprom(...)и read_program_eeprom(...). EEPROM и Flash - это две разные вещи!
м.Алин
@ m.Alin Вот как назывались «стандартные» функции, поставляемые с CCS ccompiler. Они на самом деле писать и читать Flash.
Ник Алексеев
2

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

В производстве вы запускаете программу сериализации один раз после того, как все тесты пройдены. Он создает временный HEX-файл с уникальным серийным номером, который запрограммирован в PIC, а затем временный HEX-файл удаляется.

Я не позволил бы переместить местоположение, тогда я должен найти его. Это может изменить каждую сборку, поскольку компоновщик перемещает вещи вокруг. Я сделал это для очень маленьких PIC, таких как серия 10F, где эти константы являются частью инструкций MOVLW. В этих случаях он читает файл MAP на лету, чтобы определить, где находятся эти места. У меня есть код разбора файла MPLINK MAP в библиотеке только для этой цели.

Чтобы поместить что-либо в фиксированное местоположение, определите сегмент по фиксированному адресу. Линкер будет сначала размещать такие абсолютные сегменты, а затем перемещаемые вокруг него. Не забудьте использовать CODE_PACK вместо просто CODE на PIC 18, иначе вы будете иметь дело со словами целого выражения вместо отдельных байтов. Например (только что набрал, а не запустить мимо ассемблера):

.fwinfo code_pack h'1000 '; область информации о прошивке по фиксированному известному адресу
         db h'FFFFFFFF '; серийный номер, заполненный производственной программой
         db fwtype; идентификатор типа этой прошивки
         db fwver; номер версии
         db fwseq; порядковый номер сборки
Олин Латроп
источник
2

Я бы предложил хранить серийный номер на фиксированном адресе. В зависимости от вашего компилятора / компоновщика и рассматриваемой части, вы можете выбрать несколько подходов:

  1. Определите перемещаемый раздел, который будет содержать серийный номер, используйте директиву #pragma в своем коде, чтобы принудительно ввести серийный номер в этот раздел, и укажите адрес этого раздела в спецификации ссылки.
  2. Для частей, которые могут считывать кодовую память напрямую, исключить область памяти из области, которую разрешено использовать компоновщику (то есть сказать, что эта часть, например, на четыре байта меньше, чем она есть на самом деле), а затем прочитать серийный номер в коде, используя что-то как `((unsigned long const *) 0x3FFC)`.
  3. Для частей, которые не могут считывать кодовую память напрямую, вы можете поместить инструкции «RETLW» по какому-то фиксированному адресу, а затем убедить компоновщика, что есть вызываемые функции, которые возвращают «байт» по этим адресам. Тогда можно было бы сказать, например, "out_hex (ser_byte0 ()); out_hex (ser_byte1 ()); out_hex (ser_byte2 ()); чтобы вывести байты серийного номера.
Supercat
источник
Все PIC 18F могут считывать память своих программ через механизм чтения таблиц.
Олин Латроп
Это правда. Некоторые из 14-битных частей также могут считывать память программы. Однако даже на PIC, которые могут считывать программную память, этот retlwподход часто намного быстрее (на 18-разрядных PIC a callto a retlwзанимает всего четыре цикла; использование - clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wвосемь).
суперкат
1

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

Не просил об этом, но программное обеспечение для ПК, которое я предоставляю для моего программиста Wisp648, имеет возможность считывать файл .hex, изменять определенное местоположение и записывать файл .hex обратно (в тот же или другой файл). Нет необходимости присутствовать у моего программиста. Источник доступен (на Python), лицензия разрешает любое использование: www.voti.nl/xwisp Может пригодиться, как только вы решите свою основную проблему.

Воутер ван Оойен
источник
Спасибо @Wouter van Ooijen! Я пытаюсь избежать подхода «выяснить, где хранится значение», поскольку это, скорее всего, будет означать, что значение перемещается в последовательных компиляциях, и требует, чтобы я (или какой-то грустный парень, который идет за мной), выяснил, где значение находится снова, несомненно, вносит проблемы.
Джоэл Б