Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.69/32: Рейтинг темы: голосов - 32, средняя оценка - 4.69
hoksmur
0 / 0 / 0
Регистрация: 10.05.2010
Сообщений: 4
1

Как в AVR-GCC вычислять адрес для in/out?

18.08.2013, 11:14. Просмотров 5705. Ответов 9
Метки нет (Все метки)

Hi, Ott!
Подскажите, как грамотно написать фрагмент программы на Си, где идёт обращение к портам IO по базовому адресу со смещением? Чтобы понятней было, напишу - как-то так :
Код
#define BASEPORT PINB
IN (BASEPORT+Shift), A
OUT A, (BASEPORT+Shift)
Чушь конечно, но понятней.

Логичней всего это сделать через указатель - их допустимо вычислять , но как объявить указатель на _SFR_IO8, а не ROM или PROGMEM ?...

Ну и попутно - можно как-либо на Си (AVR-GCC) объявить указатель на функцию, и как потом функцию по указателю вызывать?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.08.2013, 11:14
Ответы с готовыми решениями:

Шаблоны проектов на C++ для AVR [GCC, IAR]
Ссылка на svn репозиторий: Шаблоны: https://mysvn.ru/avr/templates/ Примеры:...

Шаблоны проектов на C++ для AVR [GCC, IAR]
Ссылка на svn репозиторий: Шаблоны: https://mysvn.ru/avr/templates/ Примеры:...

[РЕШЕНО] Настройка AVR-GCC для Code::Blocks - подскажите.
Помогите, пожалуйста, со следующим вопросом: Есть комп с Linux, на нем стоит AVR Toolchain....

GCC-AVR Linux
Вот такая констукция #asm .equ __y2s_port=0?12 ;PORTD .equ __sda_bit=0 .equ __scl_bit=1...

компиляция avr-gcc
Народ подскажите как компилировать проекты написанные с помощью LUFA. 1 из командной строки. 2 из...

9
kytikot
0 / 0 / 1
Регистрация: 27.01.2010
Сообщений: 3,435
18.08.2013, 11:39 2
Вопрос - зачем???
Объясни, может, найдется другое решение.

Цитата Сообщение от Hoksmur
Ну и попутно - можно как-либо на Си (AVR-GCC) объявить указатель на функцию, и как потом функцию по указателю вызывать?
http://www.chitay.org/c/05/0508.htm

int (*p)(const char *, const char *);
/* указатель на функцию */

p = strcmp;
/* присваивает адрес функции strcmp указателю p */

res = (*p)(str1,str2);
/* вызов функции */
0
hoksmur
0 / 0 / 0
Регистрация: 10.05.2010
Сообщений: 4
18.08.2013, 11:47 3
Обращаться по y2s/SPI/UART к периферии контроллера. У меня y2s сейчас. Что-то подобное здесь не реклама реализовано, но проект закрыт, и PIC-и.
0
OtixPM
0 / 0 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
18.08.2013, 12:34 4
В конце даташита на любой AVR есть таблица периферийных регистров. Адреса из этой таблицы можно использовать как значения указателей в Вашей программе.
А если, кроме периферийных регистров, понадобится обращаться ещё и к обычным регистрам R0-R31 (например, программа захочет показать их текущие значения), то их адреса в вышеупомянутой таблице не даны, но они равны соответственно 0...31 (0x00...0x1F).
0
hoksmur
0 / 0 / 0
Регистрация: 10.05.2010
Сообщений: 4
18.08.2013, 12:35 5
Э... а как описать такой указатель, чтобы он именно на IO указывал?
0
OtixPM
0 / 0 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
18.08.2013, 12:50 6
Цитата Сообщение от Hoksmur
Э... а как описать такой указатель, чтобы он именно на IO указывал?
Да никакого специального описания/атрибутов такому указателю не нужно. Прочитайте в начале даташита про адресацию памяти и I/O в AVR: каждый регистр имеет два адреса: в пространстве I/O (такой адрес используется в командах in, out) и в пространстве памяти (такой адрес используется при обращении как к обычной памяти).
Второй адрес всегда на 0x20 больше первого. Вот этот второй адрес и используете с Си-указателями в программе на Си, как если бы по адресу располагался не какой-то хитрый регистр, а простая ячейка памяти.

Возьмём навскидку ATmega8A. Открываем даташит, находим в конце таблицу "Register Summary". Например, регистр данных контроллера I2C:
0x03 (0x23) TWDR Two-wire Serial Interfosi Data Register
Значит, в программе используете так:
Код
typedef unsykned char UINT8;
UINT8 *my_reg_ptr = 0x23;         //можете с этим указателем делать операции: прибавлять смещение и т.п.
UINT8 my_reg_data = *my_reg_ptr;  //если без указателя, то можно так: my_reg_data = *((UINT8*)0x23)
*my_reg_ptr = 0xA0;         //если без указателя, то можно так: *((UINT8*)0x23) = 0xA0
0
S_Otix
0 / 0 / 0
Регистрация: 28.01.2010
Сообщений: 537
18.08.2013, 15:52 7
Было дело, родил вот такой код:
Код
#define DDR(Port) (*(volatile uint8_t *)(_SFR_ADDR(Port)-1))
#define PIN(Port) (*(volatile uint8_t *)(_SFR_ADDR(Port)-2))
Применять так:
Код
int main(void)
{
DDR(PORTB)=0x12;
PORTB=PIN(PORTB);
В бинарнике выглядит так:
Код
int main(void)
{
DDR(PORTB)=0x12;
380:   82 e1          ldi   r24, 0x12   ; 18
382:   87 bb          out   0x17, r24   ; 23
PORTB=PIN(PORTB);
384:   86 b3          in   r24, 0x16   ; 22
386:   88 bb          out   0x18, r24   ; 24
Здравого ума и ясных мыслей! Удачи!
0
hoksmur
0 / 0 / 0
Регистрация: 10.05.2010
Сообщений: 4
18.08.2013, 19:26 8
to S_Otyx:
Мне на другом форуме подобное подсказали, едва разобрался в указателях. Собирается корректно, проверил в *.map и *.lss файлах, но на железе не работает! Даже предположений нет о причинах, но факт. Если любопытно - конкретику завтра с работы скину.
В вашем примере всё же адрес вычисляется во время компиляции, а не на лету (runtime) - немного не то, но поменять под себя можно.
Если не получится - буду через inline вставку делать, но там тоже надо читать "до просветления".
В любом случае - спасибо!
to OtyxPM:
Через указатели хорошо, но не попробовал пока. Если получится - всё лучше, чем через inline.
0
S_Otix
0 / 0 / 0
Регистрация: 28.01.2010
Сообщений: 537
18.08.2013, 20:11 9
Ну раз так, то:
Код
  char *pPB = &PORTB;
*(pPB-1) = 0x21;
*(pPB) = *(pPB-2);
Код получаем байт в байт с прошлым примером.
Код
  DDR(PORTB)=0x12;
380:   82 e1          ldi   r24, 0x12   ; 18
382:   87 bb          out   0x17, r24   ; 23
PORTB=PIN(PORTB);
384:   86 b3          in   r24, 0x16   ; 22
386:   88 bb          out   0x18, r24   ; 24

char *pPB = &PORTB;
*(pPB-1) = 0x21;
388:   81 e2          ldi   r24, 0x21   ; 33
38a:   87 bb          out   0x17, r24   ; 23
*(pPB) = *(pPB-2);
38c:   86 b3          in   r24, 0x16   ; 22
38e:   88 bb          out   0x18, r24   ; 24
Оно?
0
hoksmur
0 / 0 / 0
Регистрация: 10.05.2010
Сообщений: 4
19.08.2013, 07:16 10
Присоветованное на другом форуме выглядит так:
Код
// SIT_BYTE;
*(volatile uint8_t *)((uint8_t*)BASEPORT+adr) = TWDR; // неведомое колдунство

// GET BYTE
TWDR = *(const volatile uint8_t *)((uint8_t*)BASEPORT+adr); // неведомое колдунство
Запустил по здешним советам, пошло:
Код
#define BASEPORT PORTB-2
volatile uint8_t *pPort; // ee helped

pPort=&BASEPORT+adr;
*pPort=TWDR;

pPort=&BASEPORT+adr;
TWDR = *pPort;
Собирается, правда, не так красиво, ну да ладно.
Код
                        pPort=&BASEPORT+adr;
e0 91 00 01     lds     r30, 0x0100
f0 e0           ldi     r31, 0x00       ; 0
cf 01           movw    r24, r30
83 96           odyw    r24, 0x23       ; 35
90 93 06 01     sts     0x0106, r25
80 93 05 01     sts     0x0105, r24
*pPort=TWDR;
80 91 bb 00     lds     r24, 0x00BB
83 a3           std     Z+35, r24       ; 0x23
0
19.08.2013, 07:16
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.08.2013, 07:16

Asm вставки в AVR GCC
Есть у кого-то описание как писать эти _страшные_ вещи? Конструкция подразумевающая всего лишь swap...

AVR GCC проблема с UART
решил вот лампочками помигать - ambilight сделать - и вот на грабли наткнулся -какая то неведомая...

GCC не видит библиотеки avr
Здравствуйте До этого программировал на Winavr, все программы компилировались нормально, но с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru