реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Сложная тема.AVR __io область как параметр функции, Нужно передать порт в функцию
dormouse
сообщение Mar 18 2005, 13:53
Сообщение #1


Участник
*

Группа: Свой
Сообщений: 22
Регистрация: 1-03-05
Из: Москва
Пользователь №: 2 980



После перехода на EC++ естественно
возникло желание передавать в конструктор информацию о порте
ввода/вывода с которым объект будет работать (если надо использовать
несколько устройств одного типа).

Иными словами - надо подключить, скажем 2 LCD.
class cLCD{ public: putchar(); ...};
cLCD LCD_A(PORTA), LCD_B(PORTB); // Можно пожертвовать читаемостью - 0x12, 0x1F
Каждый объект будет независимо работать на своём порту.

Попытки решить задачу (все безуспешные):
1. void foo(unsigned char byte){
unsigned char __io PORT_TO_WORK = @byte;//Имелось в виду @0x12
}
Неудачно, поскольку на стадии компиляции неизвестно значение byte
2. unsigned char __io * ptrPORT_TO_WORK = 0x12;
Неудачно, поскольку в IAR _НЕТ_ указателей на __io область вообще.
3. Пример из документации (стр 117)
Non-type template parameters
It is allowed to have a reference to a memory type as a template parameter, even if
pointers to that memory type are not allowed.
Example
extern int __io x;
template<__io int &y>
void foo()
{
y = 17;
}
void bar()
{
foo<x>();
}

Неудачно, компилятор говорит, что не может сделать экземплят foo,
который подходит к такому вызову...
Error[Pe304]: no instance of function template "foo" matches the argument list C:\DIY\Projects\001-IAR4-printf\main.c 77


Теперь осталось только ждать предложений, пока моя фантазия
истощена...



PS Очень нужен IAR AVR 4.10 A(B) Full (~100mb).
Go to the top of the page
 
+Quote Post
KRS
сообщение Mar 18 2005, 14:49
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(dormouse @ Mar 18 2005, 16:53)
2. unsigned char __io * ptrPORT_TO_WORK = 0x12;
    Неудачно, поскольку в IAR _НЕТ_ указателей на __io область вообще.
*


А может попробовать так
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

укзателей на __io напрямую нет конечно, но если посмотреть архитектуру AVR то можно так описать. только код не очень оптимальный будет.
Go to the top of the page
 
+Quote Post
dormouse
сообщение Mar 18 2005, 15:10
Сообщение #3


Участник
*

Группа: Свой
Сообщений: 22
Регистрация: 1-03-05
Из: Москва
Пользователь №: 2 980



Порты PORTA, DDRA, PINA - это суть макросы в IAR. Мне надо работать,скажем, с 1-wire. Для этого есть класс, конструктору которого надо передать "ногу" MC, с которой работать.

Для работы требуются все три макроса (функциональности). Я хочу работать так:
LCD lcd("A.6");

в конструкторе надо настроить как-то функции обращения к данной "ноге".
Go to the top of the page
 
+Quote Post
dormouse
сообщение Mar 18 2005, 15:19
Сообщение #4


Участник
*

Группа: Свой
Сообщений: 22
Регистрация: 1-03-05
Из: Москва
Пользователь №: 2 980



volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

Насколько я понимаю, такой строкой мы будем пытаться присвоить значение типа int самому указателю. На это компилятор ругнётся.
Go to the top of the page
 
+Quote Post
KRS
сообщение Mar 18 2005, 15:36
Сообщение #5


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(dormouse @ Mar 18 2005, 18:19)
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

Насколько я понимаю, такой строкой мы будем пытаться присвоить значение типа int самому указателю. На это компилятор ругнётся.
*


Ну надо преобразование типов поставить
((volatile unsigned char*)(0x12+0x20))
Go to the top of the page
 
+Quote Post
ZiB
сообщение Feb 20 2006, 11:58
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 122
Регистрация: 26-07-05
Из: Россия, Томск
Пользователь №: 7 109



всем, привет!
я решаю эту проблему вот так:
#define porta 0x3B
#define bit 1
........................
void Set_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) |= BitNumber;
}

void Clr_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) &= ~BitNumber;
}
.........................
Clr_Port(porta, bit);
Delay(1000);
Set_Port(porta, bit);
// можно и так
for(Byte i = 0; i<7; i++)
{
Set_Port(porta, _Bit(i));
}
Go to the top of the page
 
+Quote Post
Serega Doc
сообщение Jun 7 2010, 11:58
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 267
Регистрация: 11-11-04
Из: Одесса
Пользователь №: 1 103



Цитата(ZiB @ Feb 20 2006, 14:58) *
всем, привет!
я решаю эту проблему вот так:
#define porta 0x3B
#define bit 1
........................
void Set_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) |= BitNumber;
}

void Clr_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) &= ~BitNumber;
}
.........................
Clr_Port(porta, bit);
Delay(1000);
Set_Port(porta, bit);
// можно и так
for(Byte i = 0; i<7; i++)
{
Set_Port(porta, _Bit(i));
}


Попробовал вашу конструкцию вот что вышло в процессе компиляции в IAR 5.5 без оптимизации
Код
void Set_Port(uchar PortNumber, uchar BitNumber)
??Set_Port:
//   36 {
//   37 *((uchar*)PortNumber) |= BitNumber;
        MOV     R30, R16
        LDI     R31, 0
        LD      R18, Z
        OR      R18, R17
        ST      Z, R18
//   38 }
        RET
//   39

        RSEG CODE:CODE:NOROOT(1)
//   40 void Clr_Port(uchar PortNumber, uchar BitNumber)
??Clr_Port:
//   41 {
//   42 *((uchar*)PortNumber) &= ~BitNumber;
        MOV     R18, R17
        COM     R18
        MOV     R30, R16
        LDI     R31, 0
        LD      R19, Z
        AND     R19, R18
        ST      Z, R19
//   43 }
        RET
//   44
//   45

        RSEG CODE:CODE:NOROOT(1)
//   46 int main()
main:
//   47 {
// Пример работы с портом
//   48     PORTB = 10;
        LDI     R16, 10
        OUT     0x18, R16
//   49     PORTB++;
        IN      R16, 0x18
        INC     R16
        OUT     0x18, R16
//   50  // Ваши процедуры
//   51     Clr_Port(porta, bit);
        LDI     R17, 1
        LDI     R16, 24
        RCALL   ??Clr_Port
//   52     
//   53     Set_Port(porta, bit);
        LDI     R17, 1
        LDI     R16, 24
        RCALL   ??Set_Port
//   54     
//   55
//   56   return 0;
        LDI     R16, 0
        LDI     R17, 0
        RET
        REQUIRE _A_PORTB
//   57 }

Что то тут не то sad.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 7 2010, 12:10
Сообщение #8


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Serega Doc @ Jun 7 2010, 15:58) *
Попробовал вашу конструкцию вот что вышло в процессе компиляции в IAR 5.5 без оптимизации
Что то тут не то sad.gif

А теперь попробуйте с оптимизацией.
Может быть, получится то самое?


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Serega Doc
сообщение Jun 7 2010, 12:35
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 267
Регистрация: 11-11-04
Из: Одесса
Пользователь №: 1 103



Цитата(MrYuran @ Jun 7 2010, 15:10) *
А теперь попробуйте с оптимизацией.
Может быть, получится то самое?

Вот что с оптимизацией
Код
13 void Set_Port(uchar PortNumber, uchar BitNumber)
??Set_Port:
//   14 {
//   15 *((uchar*)PortNumber) |= BitNumber;
        MOV     R30, R16
        LDI     R31, 0
        LD      R16, Z
        OR      R16, R17
        REQUIRE ?Subroutine0
       ;               // Fall through to label ?Subroutine0
//   16 }

        RSEG CODE:CODE:NOROOT(1)
?Subroutine0:
        ST      Z, R16
        RET
//   17

Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит. Да и врядли вообще можно написать что то требуемое потому как в ассемблере IN и OUT конструкции используются с константой и в них номер регистра вообще нельзя передать.
Так что нужно писать таблицу типа и делать переходы на эти метки или как то с помощью кейсов описывать. Иначе на мой взгляд никак.
Код
??RD_PORTB
IN 0x18,R16
RET;
??RD_PORTC
IN 0x15,R16;
RET;
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jun 7 2010, 15:59
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(Serega Doc @ Jun 7 2010, 15:35) *
Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит. Да и врядли вообще можно написать что то требуемое потому как в ассемблере IN и OUT конструкции используются с константой и в них номер регистра вообще нельзя передать.

Никогда не пробовал, если честно, но по-моему вы заблуждаетесь.

Если посмотреть даташит на atmega8, к примеру, то в разделе SRAM Data Memory есть таблица распределения ОЗУ (Figure 8. Data Memory Map). В ней, насколько я понимаю, показано, что область IO отображается на память со смещением в 0x20. Похоже именно это имел ввиду KRS в первом же посте. Таким образом работать с указателями возможно. Хотя, повторюсь ещё раз, сам лично я не пробовал.
Есть ещё проблема с теми портами, которые подлежат обращению ч/з LD/ST, но это тоже можно описать.

Хотя стоит ли всё это потраченных сил? Не проще ли написать это всё более размашисто и менее универсально? Как правило, работа с оборудованием - ничнтожная часть проекта.
Go to the top of the page
 
+Quote Post
ae_
сообщение Jun 8 2010, 12:43
Сообщение #11


Участник
***

Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695



Цитата(Serega Doc @ Jun 7 2010, 21:35) *
...Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит...

"ST Z,R16" невозможно соптимизировать в "OUT 0x18,R16" потому что это разные типы адресации, косвенная и прямая, и в первом случае Z - не определено.
вот "STS 0x38,R16" уже можно соптимизировать в "OUT 0x18,R16", здесь заранее известно, куда записать R16.
или все эти три инструкции вместе:
LDI ZL,0x18+0x20
LDI ZH,0
ST Z,R16
можно заменить на одну "OUT 0x18,R16", но не как в первом случае.

Вообще, к любому РОН и порту В/В можно обратится, как к ОЗУ, т.к. все они находятся в одном сегменте данных:
0x00-0x1F - R0...R31
0x20-0x5F - порты в/в, к которым можно обращаться инструкциями IN/OUT, но для IN/OUT адреса меньше на 0x20, т.е. 0x00-0x3F
0x60-0xFF - порты в/в, до которых IN/OUT уже не дотягивается и к ним нужно обращаться, как к ОЗУ
0x100-... - ОЗУ
Например: "STS 0x05, R7" = "MOV R5, R7", но первый вариант занимает 2 слова и выполняется 2 цикла, против 1/1, поэтому мало интересен,
точно также, как и "STS 0x38,R16" = "OUT 0x18,R16", те же 2/2 против 1/1

косвенная адресация более применима:
Код
CLR ZL
CLR ZH
clear:       ; обнуление регистров R0...R15
ST  Z+, ZH
CPI ZL, 16
BRLO clear

Если хочется универсальности, косвенное обращение через X, Y, Z-регистры к портам в/в - приемлемое решение.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:35
Рейтинг@Mail.ru


Страница сгенерированна за 0.01462 секунд с 7
ELECTRONIX ©2004-2016