Данные, которые вы описываете (полное 24-битное использование памяти программы для хранения данных), не могут быть определены и инициализированы в C и не могут быть прочитаны напрямую через C; единственный способ получить к нему доступ - это инкапсулировать в C-вызываемую ассемблерную функцию или встроенную функцию.
Здесь действительно два вопроса:
как хорошо играть с компилятором, ассемблером и компоновщиком, чтобы, когда вы определяете свои 24-битные данные в файле сборки как перемещаемые данные с символическим именем D1
, а не безымянные данные по фиксированному адресу, компилятор может видеть эту переменную определить его адрес
как получить доступ к данным
На 2-й вопрос (как получить доступ к данным) дан ответ для деталей 33EP в DS70613C и должен быть дан ответ для деталей 33FJ в DS70204C (но примеры в руководстве по 33FJ используют только младшие 16 бит). Вот пример фрагмента кода из справочного руководства 33EP, который работает для деталей 33EP + должен для 33FJ (у меня нет легко доступного устройства 33FJ):
(примечание: код использует int
, тогда как было бы лучше использовать uint16_t
и #include <stdint.h>
)
int prog_data[10] __attribute__((space(prog))) =
{0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};
unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;
int main(void){
TBLPAG = __builtin_tblpage (prog_data);
tableOffset = __builtin_tbloffset (prog_data);
/* Read all 10 constants into the lowWord and highWord arrays */
for (loopCount = 0; loopCount < 10; loopCount ++)
{
lowWord[loopCount] = __builtin_tblrdl (tableOffset);
highWord[loopCount] = __builtin_tblrdh (tableOffset);
tableOffset +=2;
}
while(1)
;
}
Вы заметите , что функции встроенных __builtin_tblrdl()
и __builtin_tblrdh()
используются для чтения низких и высоких 16-битовых слов данных из памяти программ, и __builtin_tblpage() and __builtin_tbloffset()
может быть использована для извлечения страницы и смещение адреса. В этом конкретном примере массив highWord всегда равен 0, а массив lowWord соответствует prog_data, определенному и инициализированному в C.
Обратите внимание, что здесь не используются указатели! Хотя можно использовать обычные переменные, помеченные тегом const
, чтобы они находились с помощью компоновщика в программном пространстве, доступном только для чтения, и чтобы вы могли читать память с использованием стандартных методов указателя C, а компилятор автоматически управляет регистрами подкачки для вас вы можете хранить только 16-битные данные. Вам нужно получить доступ к встроенным функциям TBLRDL и TBLRDH, чтобы получить все 24 бита данных.
Что касается того, как хорошо играть с компилятором / компоновщиком / etc, вы должны обмануть компилятор и сказать ему, что он видит только 16-битные данные. Вот пример, который работал, чтобы получить переменную D1, объявленную в другом месте:
#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];
#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
TBLPAG = page;
while (len-- > 0)
{
uint16_t lo = __builtin_tblrdl (offset);
uint16_t hi = __builtin_tblrdh (offset);
*pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
offset += 2;
}
}
...
uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);
Это правильно читает 24-битные значения и сохраняет их в нижних 24 битах uint32_t. Переменная extern D1, объявленная в C, является фиктивной переменной, которая используется только для того, чтобы получить начальный адрес, используя преимущества совместной работы компилятора / ассемблера / компоновщика. Встроенные функции выполняют остальную часть работы.
Чего я не знаю, так это как автоматически получить размер данных, так как они определены + инициализированы в сборке.