Обсуждаем контроллеры компании Atmel.
Ответить

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 17:51:26

Просто может есть еще какое-то решение, не использовать MOSI.

Так я же дал еще один способ :-) не подходит?

Спойлер/* Функция выдачи байта со значением 0x00 */
out_00:
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
RET
/* Функция выдачи байта со значением 0x01 */
out_01:
SBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
RET
/* Функция выдачи байта со значением 0x02 */
out_02:
CBI $0B, 7
SBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
RET

/* Функция выдачи байта со значением 0x02 */
out_02:
CBI $0B, 7
SBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
CBI $0B, 7
RET

....
/* Функция выдачи байта со значением 0xfe */
out_fe:
CBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
RET

/* Функция выдачи байта со значением 0xff */
out_ff:
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
SBI $0B, 7
RET


Данные функции имеют одиноковый размер, т.е. если они идут подряд, вычислить адрес нужной функции - не проблема.

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 19:21:39

Так я же дал еще один способ :-) не подходит?
Данные функции имеют одиноковый размер, т.е. если они идут подряд, вычислить адрес нужной функции - не проблема.
Подходит, объем кода только будет шикарный. Надо попробовать.

Добавлено after 7 minutes 31 second:
Отлично, быстрее не сделаешь, разве что кварц менять.
СпойлерИзображение

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 19:36:26

Dimon456, в твоем примере, время выдачи байта зависит от значения байта. По крайней мере видно, что компилятор так нагенерил (может оптимизация не включена). Если ты допишешь все 256 case-ов, увидишь что значение 255 сдвигается долго. Надо именно вычислить смещение, а не перебирать все варианты.

посмотри как написать свою функцию эффективно на ассемблере, пока приходит идея использовать SBRC, SBRS команды. А так надо смотреть, количество тактов для выполнения всех комманд есть в документации. Когда был студентом, у нас была игра - написать небольшую (типа твоей) функцию, чтобы она выполнялась максимально быстро. Вот тебе и надо поигать в эту игру. :-)

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 20:00:26

Да, действительно, не хилая задачка, да и код шикарный будет.
СпойлерИзображение

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 20:11:07

Навскидку 4608байт займут 256 функций вывода (я не внимательно считал). Но это самый быстрый вариант при выдаче байта - нет ветвлений. Можно уйти от 256 функций, съэкономив флеш, но будет медленней.

Re: WinAvr в вопросах и ответах

Пн окт 09, 2017 20:14:37

Почему код CVAVR обсуждается в теме WinAVR?!

Структуры в PROGMEM

Пн окт 09, 2017 21:30:04

Нет, конечно, потрепаться о CVAVR в теме про WinAVR - это, несомненно, круто! А вот как с моим вопросом?

Ладно, структуры в PROGMEM, действительно, нереальны. А может выйдет как-нибудь запихнуть два байта двоичного кода внутрь текстовой строки, преобразовав эти коды макросом? Типа, пишу My_Macro(10560,"какой-то текст"); и получаю "\0x40\0x29\какой-то текст", где 0х40 - остаток от деления 10560 на 256, а 0х29 - целая часть результата этого деления, т е. частного? Или что-то подобное?

Блин, ну какой убогий макроязык в этих Сях!.. На макроязыке любого ассемблера от "больших" компьютеров такое сделать - как два байта переслать, а тут!.. :kill:

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 07:10:19

afz писал(а):структуры в PROGMEM, действительно, нереальны
еще как реальны! но инициализировать их СТРОКАМИ не очень удобно. можно, но чуть-чуть геморно. всё дело в том, что AVR-GCC не может одновременно присваивать строковое значение полю структуры и объявлять строковую константу. делать это придётся отдельно... то есть как-то так:
Код:
typedef struct{
   int a;
   char b;
   char *str;
} my_struct;

PROGMEM char my_str1[] = "string 1";
PROGMEM char my_str2[] = "string 2";
PROGMEM char my_str3[] = "string 3";
PROGMEM char my_str4[] = "string 4";

#define str_init(x,y,z) {.a=x, .b=y, .str=z}

PROGMEM my_struct array[4] = {
   str_init(1,2,my_str1),
   str_init(3,4,my_str2),
   str_init(5,6,my_str3),
   str_init(7,8,my_str4)
}


Добавлено after 1 minute 50 seconds:
Очень рекомендую применять не WinAVR, а сборку AVR-GCC версии свежее 4 (лично я пользуюсь 6.2.2) - там уже определено пространство __flash, что позволяет работать с массивами, строками и структурами во flash практически так же просто, как и с ОЗУ - никаких pgm_read_xxx более не требуется!

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 08:12:50

Как вариант, для более простого кода можно попробовать инициализировать не строками, а массивами char-ов определённой длины. Правда, при этом часть памяти будет потрачена впустую.
Код:
typedef struct{
   uint16_t freq;
   char name[16];
} my_struct;

const my_struct array[] PROGMEM = {
    {9890, "Russian"},
    {9950, "Unistar"},
};

Не уверен в корректности кода (в смысле, не проверял), но компилируется он вроде как без ошибок.

Re: Структуры в PROGMEM

Вт окт 10, 2017 13:46:38

afz, чуть подправил пример от ARV, чтобы все определения (радиостанций) поместить в одно место. Почти как ты хотел :-) (предполагается, что "freq" структуры _radio_t является уникальным):

Спойлер
Код:
#define RADIO_LIST                 \
   RADIO_ITEM(10450, "string 1")   \
   RADIO_ITEM(10520, "string 2")   \
   RADIO_ITEM(10640, "string 3")   \
   RADIO_ITEM(10680, "string 4")

typedef struct _radio_t {
   int freq;
   const char *name;
} radio_t;

/* Объявляем строки */
#define RADIO_ITEM(f,s) PROGMEM char radio_name_##f [] = s;
   RADIO_LIST
#undef RADIO_ITEM

/* Объявляем массив, в котором указатели на объявленные ранее строки */
#define RADIO_ITEM(f,s) { .freq=f, .name=radio_name_##f },
PROGMEM radio_t radio_array [] = {
   RADIO_LIST
};

#define RADIO_LIST_SZ (sizeof (radio_array)/sizeof(radio_t))

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 13:52:22

viiv писал(а):чуть подправил пример
вот это здорово! сам мучился всегда с разбросанными в разных местах строками и связанными с ними логически остальными вещами - беру на вооружение ваш подход! :beer:

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 15:38:53

Не уверен в корректности кода (в смысле, не проверял), но компилируется он вроде как без ошибок.

Раз скомпилировал, то легко посмотреть во что это скомпилировалось :-) Например, если задать ключик "-S", то в выходном ассемблерном файле можно посмотреть все ли было сделано так, как задумывалось. У меня не WinAVR, а классический кросс gcc под линукс: Ваш код поместил массив структур в секцию ".progmem.data", - все как и было задумано

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 15:58:13

Да, что-то я и забыл про .lss файл, который у меня Makefile делает
Изображение

Re: WinAvr в вопросах и ответах

Вт окт 10, 2017 18:22:45

В общем так:
Спойлер
Код:
// Создаем функции с одинаковым количеством параметров
// и соответствующими типами, а так же возвращаемым типом

void m0 (void) {
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
}

void m1 (void) {
     PORT_VID.VID_PIN = 1;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
}

void m2 (void) {
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 1;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
     PORT_VID.VID_PIN = 0;
}

// Я три создал, для проверки что это будет работать

 // создаем новый прототип (в данном случае указатель на функцию)
  typedef  void (*fptr)(void);
   
  fptr arr[3]; // объявляем массив функций в данном случае из трех элементов
  // помещаем в массив функции указывая их имена (имя функции это и есть указатель на нее)
    arr[0] = m0;
    arr[1] = m1;
    arr[2] = m2;

//Ну и волшебный
#define COLUMN(r) arr[font[r][fontline]]();          // Результат 3.7500us

//Надпомню #define COLUMN(r) SPDR=font[r][fontline];                 // Выполнялся за 1.5625us

Re: WinAvr в вопросах и ответах

Вт окт 17, 2017 22:13:23

Доброго времени суток. Раздела по AVR Toolchain не нашел, поэтому спрошу здесь. Вчера стоял AVR Toolchain 3.3, сегодня снес и поставил 3.4 (новее, значит лучше, ага...). Вчера прога компилировалась без ошибок, сегодня на строке
Код:
char OK[] PROGMEM = "OK";

Выдает error: variable 'OK' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
Как изменить запись, чтобы ошибка пропала ? Студия 4.19.

Re: WinAvr в вопросах и ответах

Вт окт 17, 2017 22:44:23

Добавить const перед типом. Странно, что пропускало без этого атрибута, эти данные должны обязательно объявляться константами.

Re: WinAvr в вопросах и ответах

Ср окт 18, 2017 06:53:17

Пока_без_кота писал(а):новее, значит лучше, ага...
мне показалось, что avr-gcc 4.9.2 и 5.2.1 выдают более компактный результат компиляции. ну а вообще максимально новая версия, которой я пользуюсь, имеет номер 6.1.1
Пока_без_кота писал(а):Как изменить запись, чтобы ошибка пропала ?
попробуйте так
Код:
const __flash char OK[] = "OK";
если скомпилируется, то для доступа к байтам строки уже не потребуется применять pgm_read_byte, можно будет сразу работать, как с обычной переменной. разумеется, это относится не только к строкам, но и к любым другим "переменным" во flash

только с указателями будьте осторожнее, потому что "указатель на данные во flash" и "указатель во flash на данные" - две большие разницы

Re: WinAvr в вопросах и ответах

Ср окт 18, 2017 07:48:10

Нет, скомпилировалось только, если просто добавить const
Код:
const char OK[] PROGMEM = "OK";

И теперь выдает warning: passing argument 1 of 'SendStr_P' discards 'const' qualifier from pointer target type [enabled by default] на функции
Код:
// Отправка строки из флеша в UART =================
void SendStr_P(char *string)                     // На входе указатель на символ строки
{
   while (pgm_read_byte(string) != '\0')            // Пока байт строки не 0 (конец строки)
   {
      SendByte(pgm_read_byte(string));            // Мы продолжаем слать строку
      string++;                              // Не забывая увеличивать указатель, выбирая следующий символ строки
   }
}

Смысл варнинга мне понятен, но вот как подправить, я не знаю.
Насчет не самой последней версии. Это последняя версия с сайта Атмел, которая идет одним екзешником и ее легко может проинсталить любой новичек. Все что позже, поставляеться каким-то набором файлов, и я незнаю, как его установить.
Последний раз редактировалось Пока_без_кота Ср окт 18, 2017 07:55:56, всего редактировалось 2 раз(а).

Re: WinAvr в вопросах и ответах

Ср окт 18, 2017 07:55:08

Пока_без_кота писал(а):но вот как подправить, я не знаю
да точно так же: раз указатель "на константу", то и писать его тип надо аналогично
Код:
void SendStr_P(const char *string)


Добавлено after 51 second:
P.S. __flash, наверное, в более поздних версиях компилятора добавилось - рекомендую перейти на посвежее версию.

Re: WinAvr в вопросах и ответах

Ср окт 18, 2017 07:58:16

Ха... Я думал точно так, как Вы сказали, но если я так делал, мне вместо варнинга выдавался уже error: conflicting types for 'SendStr_P'. Посчитав, что варнинг лучше чем еррор, я оставил как было...
Ответить