Перейти к содержанию
    

Вопрос по HI-Tech C

Вобщем есть такой вопросик:

Есть подпрограмма(функция или процедура-не важно).

В ней таблица вида

void Table1(void)
{
#asm
dw 0x3FF,0x3FF// и так далее...
#endasm
}

почему asm,dw 0x... спросите вы: для того, что бы я мог использовать все 14 бит flash памяти. можно задать как массив во флэш,но при реализации компилятор сделает таблицу вида:

 retlw 0xFF
retlw 0x1F

и т.д.

 

собственно, сам вопрос: как можно считать эти данные внутри функции Table1 и если не вызывается данная функция, как заставить компилятор её не исключать при сборке.

 

Считать флэш у меня получается, а присвоить присвоить переменной адрес функции-не получается.

Да, проц = PIC16F876A и(или) PIC16F886

Изменено пользователем DenisIV

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если это просто данные, зачем их описывать как функцию ? нужно делать массив констант

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если это просто данные, зачем их описывать как функцию ? нужно делать массив констант

Объясняю: данные размером 8 килобайт. в памяти FLASH контроллера 14 килобайт (8 килослов размером 14 бит)

если я задам массив из 8 килобайт, компилятор сгенерит код типа retlw 0xFF и т.д. т.е. будет использовано 8 бит из 14-и.

этот код будет весить 8 килослов(14-битных, а не 8!!!), т.е. 100% FLASH памяти контроллера.

 

мне же мужно считать 14-битные данные из FLASH, выровнять на границу в 8 бит и т.д (дальше не вопрос)

я думаю, в 6 килобайт оставшихся точно помещу распаковку(выравнивание) =))

 

ваш совет полезен только в случае, если массив менее 8кб (8192-длина программы)

а здесь другое...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Объявление:

void Table1(void)
{
#asm
    global  MyTable               // Используем отдельную метку на тот случай, когда компилятор вдруг
                                  // решит добавить какой-нибудь код в начало функции (вроде clrf STATUS)
MyTable:
    dw 0x3FFF,0x3FFF// и так далее...
#endasm
}

 

Считывание адреса:

void main (void)
{
    asm("   fncall  _main, _Table");   // Говорим компилятору, что функция используется без прямого вызова,
                                       // чтобы он ее включил в код
    ...
    #asm
        global MyTable
        bsf     _STATUS, 6
        movlw   low(MyTable)
        movwf   EEADR
        movlw   high(MyTable)
        movwf   EEADRH
        bcf     _STATUS, 6
    #endasm
    ...
}

 

P.S. А вариант со сжатием данных по подойдет? Т.е. сделать обычный массив через const char Table[]={...}, и добавить функцию-распаковщик.

Изменено пользователем testerplus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Огромное вам сапасибо, testerplus , я более ёмкого и конкретного ответа даже не ожидал.

Буду тестировать на проекте как проснусь, сразу отпишусь.

Алгоритм со сжатием не подойдёт, так как данные уже упаковны не хуже GSM упаковки... Но всё равно биг спс !!!

Я думаю, считывание типа Temp=FLASH_READ(MyTable+OffSet) должно пройти...

Есть ещё пара мелких локальных вопросов, которые я хотел бы задать, но это потом...

Адреналин, оказывается, вырабатывается не только в случае опасности, а так же в случае удачной компиляци... :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю, считывание типа Temp=FLASH_READ(MyTable+OffSet) должно пройти...

Такой фокус не пройдет (пройдет только на STD-версии компилятора и для ПИКа с ROM < 2k, да и то, если переобъявить метки "MyTable" -> "_MyTable" и в начале файла добавить объявление прототипа: void MyTable(void)).

 

Метка, объявленная в asm из Си не будет видна. Так что только через асм. Удобно будет организовать в виде функции, но это уже Вам решать:

int GetMyTable (int offset)
{
    #asm
        global MyTable
        movlw   low(MyTable)             // Прибавляем адрес MyTable к offset
        addwf   _Table$offset + 0, f
        movlw   high(MyTable)
        btfsc   _STATUS, 0
        addlw   1
        addwf   _Table$offset + 1, f
    #endasm
    return FLASH_READ(offset);
}

...

// обращаемся так:

    i = GetMyTable(100);
    ...
    j = GetMyTable(i + 18);
    ...
    и т.д.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня прошло так:

void MyArray(void)
{
#asm
dw 0x3FF0,0x1A55
#endasm
}

void main(void)
{unsigned int Temp,Tmp;
asm("   fncall  _main, _MyArray"); 
Temp=&MyArray;  
Tmp=FLASH_READ(Temp);
}

Только вот указатель на функцию компилируется неправильно. Либо я его неправильно описал.

Как я понимаю:

Temp - прямая адресация к ячейке.

*Teмp - адресация к данным через указатель (как к регистру INDF)

&Temp - адресация к самому указателю (как к регистру FSR)

в итоге у меня почему-то значение в Temp не совпадает с адресом самой функции.

А так строчка

asm("   fncall  _main, _MyArray");

мне очень помогла.

Не хотелось бы прибегать к асму, т.к. программа планируется быть носимой на другие платформы.

предыдущий рабочий вариант был таков:

unsigned int MyArray(void)
{
#asm
movlw low ($+5)
movwf ?_MyArray
movlw high($+3)
movwf ?_MyArray+1
return
dw 0x3FF0,0x1A55
#endasm
return 0;// для того, чтобы компилятор увидел явный возврат из функции на С (команды asm он в расчёт не берёт)
}

void main(void)
{
unsigned int i,Tmp,Temp;
Temp=MyArray();
Tmp=0;
for(i=0;i<1024;i++)
    {Tmp=Tmp+FLASH_READ(Temp+i);}
}

но в начале функции команды asm не дадут перейти на другую платформу... =((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только вот указатель на функцию компилируется неправильно. Либо я его неправильно описал.

Как я понимаю:

Temp - прямая адресация к ячейке.

*Teмp - адресация к данным через указатель (как к регистру INDF)

&Temp - адресация к самому указателю (как к регистру FSR)

в итоге у меня почему-то значение в Temp не совпадает с адресом самой функции.

Я выше описывал, что так не получится. HTPICC (и STD, и PRO) при объеме ROM > 2K будут строить таблицы переходов для всех функций, к адресам которых есть обращения в программе. Т.е. Ваша операция &MyArray вернет не адрес самой функции, а адрес вызова через таблицу переходов

для STD-версии или номер элемента в таблице переходов для PRO-версии (кстати, у Вас каккая?)

 

Кроме того, HTPICC легко первыми инструкциями в функции вставит:

    bcf    status, rp0
    bcf    status, pr1

Если они будут добавлены, то вся таблица сместится, поэтому обращение может быть только через внутреннюю метку.

 

на какие платформы планируется перенос? dw не везде задается одинаково.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я выше описывал, что так не получится. HTPICC (и STD, и PRO) при объеме ROM > 2K будут строить таблицы переходов для всех функций, к адресам которых есть обращения в программе. Т.е. Ваша операция &MyArray вернет не адрес самой функции, а адрес вызова через таблицу переходов

для STD-версии или номер элемента в таблице переходов для PRO-версии (кстати, у Вас каккая?)

Можно поподробнее? Есть ли доступ к таблице переходов?

PRO 9.65

Кроме того, HTPICC легко первыми инструкциями в функции вставит:

    bcf    status, rp0
    bcf    status, pr1

Если они будут добавлены, то вся таблица сместится, поэтому обращение может быть только через внутреннюю метку.

даже если сместится, можно хоть как-нибудь не прибегая к асму вытащить адрес функции и засунуть в какую-нибудь переменную?

на какие платформы планируется перенос? dw не везде задается одинаково.

на AVR и x51.

ну в AVR с dw нормально, только точка перед ней нужна, с 51 проблем никаких вроде.

dw не самая большая проблема.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно поподробнее? Есть ли доступ к таблице переходов?

PRO 9.65

 

Тут все не очень просто. В ПРО-версиях (кажется с версии 9.60pl4) есть внутренняя константа fpbase (не доступная через Си, по крайней мере, я не добрался до нее). К ней можно обратиться только через asm:

int i;
...
asm(" movlw   low(fpbase)");
asm(" movwf   _i + 0");
asm(" movlw   high(fpbase)");
asm(" movwf   _i + 1");

 

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

 

Но также доступой становится константа с префиксом fp__ (опять же через ассемблер). Если функция называется MyArray, то адрес перехода на эту функцию в таблице переходов будет доступен через константу fp__MyArray.

 

даже если сместится, можно хоть как-нибудь не прибегая к асму вытащить адрес функции и засунуть в какую-нибудь переменную?

Я пока не находил таких механизмов.

на AVR и x51.

ну в AVR с dw нормально, только точка перед ней нужна, с 51 проблем никаких вроде.

dw не самая большая проблема.

 

Я про разные платформы спросил вот к чему: учитывая, что в трех перечисленных платформах dw описывается по-разному, то все равно придется делать какие-то платформозависимые куски кода и выбирать их директивами препроцессора #ifdef. А раз так, то совершенно спокойно можно использовать встроенный asm по той схеме, которую я привел в функции GetMyTable() (тремя-четырьмя постами выше). Вот эту функцию и нужно будет сделать платформозависимой. Весь остальной код будет переносимым, т.к. будет содержать только вызов этой функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ясно. ну в этом случае мне выгоднее использовать конструкцию, которую я ранее приводил, когда я вызываю функцию, а в теле функции асмом отдаётся собственный код адреса и далее dw 0x.. и т.д.

 

Да, позвольте дать совет не использовать конструкции вида

asm ('movlw 0x00');
asm ('movwf MyVar');

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

лечше используйте блоками:

#asm
movlw 0x00
movwf MyVar
#endasm

Это хоть какая-то гарантия будет от перемешивания команд... (IAR для AVR точно очень любит такие фокусы, я насмотрелся...)

Ну тема с доступом к массиву полагаю,закрыта...

Хотелось бы ещё спросить про аппаратный I2C мастер. У меня ну никак не получилось заставить его работать. Может какие тонкости есть в этом деле?

Я попытался повторить эту демку на PIC16F886 и сколько не бился, так и не смог запустить аппаратно I2C. Пришлось программно симулировать.

В даташите вроде не отличаются I2C у 876A и 886.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, позвольте дать совет не использовать конструкции вида

asm ('movlw 0x00');
asm ('movwf MyVar');

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

лечше используйте блоками:

#asm
movlw 0x00
movwf MyVar
#endasm

Это хоть какая-то гарантия будет от перемешивания команд... (IAR для AVR точно очень любит такие фокусы, я насмотрелся...)

Спасибо, хотя я с этим никогда не сталкивался.

 

Хотелось бы ещё спросить про аппаратный I2C мастер.

Если честно, никогда не работал с аппаратным i2c в ПИКах

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...