Устройство: dsPIC33FJ128GP802
У меня есть некоторые * .s файлы следующим образом
.global _D1
.section .speex, code
_D1:
.pword 0x66C821, 0x1B0090, 0xD96C36, 0x9B60B0, 0xDD4E36, 0xBF4E53
.pword 0xD1098B, 0x719BD9, 0x873989, 0x003B69, 0x279035, 0xED4244
.pword 0xE1403C, 0x54D439, 0x826550, 0xC59627, 0xDD0432, 0x88FA29
Я объявил то же самое в * .h
extern void D1(void);
Теперь я передаю D1 в функцию чтения таблицы
nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);
Моя проблема в том, что, если адрес D1 выше 0X8000, процедура не является правильной. Я пробовал большие и маленькие модели кода, но результат один и тот же. Я думаю, что это связано с 16-битным ограничением указателей. Есть ли какой-либо метод для доступа к абсолютному адресу D1 непосредственно из кода. Может быть что-то вроде встроенной функции или макроса.
microcontroller
pic
microchip
compiler
Санееш А.Т.
источник
источник
D1
представлять функцию или массив данных?const short D1[]
.Ответы:
Данные, которые вы описываете (полное 24-битное использование памяти программы для хранения данных), не могут быть определены и инициализированы в C и не могут быть прочитаны напрямую через C; единственный способ получить к нему доступ - это инкапсулировать в C-вызываемую ассемблерную функцию или встроенную функцию.
Здесь действительно два вопроса:
как хорошо играть с компилятором, ассемблером и компоновщиком, чтобы, когда вы определяете свои 24-битные данные в файле сборки как перемещаемые данные с символическим именем
D1
, а не безымянные данные по фиксированному адресу, компилятор может видеть эту переменную определить его адрескак получить доступ к данным
На 2-й вопрос (как получить доступ к данным) дан ответ для деталей 33EP в DS70613C и должен быть дан ответ для деталей 33FJ в DS70204C (но примеры в руководстве по 33FJ используют только младшие 16 бит). Вот пример фрагмента кода из справочного руководства 33EP, который работает для деталей 33EP + должен для 33FJ (у меня нет легко доступного устройства 33FJ):
(примечание: код использует
int
, тогда как было бы лучше использоватьuint16_t
и#include <stdint.h>
)Вы заметите , что функции встроенных
__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, объявленную в другом месте:
Это правильно читает 24-битные значения и сохраняет их в нижних 24 битах uint32_t. Переменная extern D1, объявленная в C, является фиктивной переменной, которая используется только для того, чтобы получить начальный адрес, используя преимущества совместной работы компилятора / ассемблера / компоновщика. Встроенные функции выполняют остальную часть работы.
Чего я не знаю, так это как автоматически получить размер данных, так как они определены + инициализированы в сборке.
источник
Не конвертируйте его в unsigned long и обратно. Просить неприятностей. Вы в основном врете компилятору. Правильное объявление для nowPlaying.file1:
И аналогично для функции ():
и удалите все типы.
Или, если @PeterJ предполагает, что это данные, они должны быть объявлены как extern short D1 [] в обоих местах: и вам не нужен ассемблер; Вы могли бы объявить все это в C как const short D1 [] = {...}; Компилятор должен поместить его в сегмент кода, как он есть.
источник
Кажется, простой ответ - написать подпрограмму на ассемблере. Если я правильно помню, C30 не обращается к памяти программ как к данным с использованием 24-битных указателей. В лучшем случае он может получить доступ к памяти программ через окно PSV, но тогда вы можете видеть только младшие 16 битов каждого 24-битного слова памяти программ.
Было бы очень просто написать программу на ассемблере, которая вызывается из C30, которая возвращает 24-битные данные с 24-битным адресом памяти программ. Однако, являются ли ваши данные набором 24-битных значений или действительно списком байтов, которые упакованы по 3 на слово? Если последнее, то это еще проще. Напишите программу на ассемблере, которая дает вам представление байтовых адресов памяти программы. Адрес все равно должен был бы быть 24 битами, но значения данных теперь только 8 битов.
Или просто напишите всю программу на ассемблере. Если вы делаете этот вид низкоуровневой синхронизации байтов и упаковки памяти, это, вероятно, проще. В ассемблере вы можете просто делать то, что вы хотите, так, как машина хочет это сделать. В C вы должны выяснить, какие заклинания нужно шептать компилятору, чтобы он написал для вас машинный код. Иногда проще сделать это самостоятельно. Архитектура dsPIC особенно проста в написании ассемблерного кода, определенно проще, чем PIC 16.
источник
__builtin_tblrdX()
функции. Я согласен с вами + получил удовольствие от вашей фразы "В C вы должны выяснить, какие заклинания нужно шептать компилятору". По иронии судьбы, если вы действительно пытаетесь снизить максимальную производительность, иногда__builtin()
функции лучше, потому что компилятор может оптимизировать способ генерации кода, в то время как он должен обрабатывать кодированные вручную функции сборки как черные ящики, которые он не может изменить ,