|
|
  |
Сложная тема.AVR __io область как параметр функции, Нужно передать порт в функцию |
|
|
|
Mar 18 2005, 13:53
|
Участник

Группа: Свой
Сообщений: 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).
|
|
|
|
|
Mar 18 2005, 14:49
|

Профессионал
    
Группа: Модераторы
Сообщений: 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 то можно так описать. только код не очень оптимальный будет.
|
|
|
|
|
Mar 18 2005, 15:10
|
Участник

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

|
Порты PORTA, DDRA, PINA - это суть макросы в IAR. Мне надо работать,скажем, с 1-wire. Для этого есть класс, конструктору которого надо передать "ногу" MC, с которой работать.
Для работы требуются все три макроса (функциональности). Я хочу работать так: LCD lcd("A.6");
в конструкторе надо настроить как-то функции обращения к данной "ноге".
|
|
|
|
|
Mar 18 2005, 15:19
|
Участник

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

|
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;
Насколько я понимаю, такой строкой мы будем пытаться присвоить значение типа int самому указателю. На это компилятор ругнётся.
|
|
|
|
|
Mar 18 2005, 15:36
|

Профессионал
    
Группа: Модераторы
Сообщений: 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))
|
|
|
|
|
Jun 7 2010, 11:58
|

Местный
  
Группа: Свой
Сообщений: 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 } Что то тут не то
|
|
|
|
|
Jun 7 2010, 12:35
|

Местный
  
Группа: Свой
Сообщений: 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;
|
|
|
|
|
Jun 7 2010, 15:59
|
Гуру
     
Группа: Свой
Сообщений: 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, но это тоже можно описать. Хотя стоит ли всё это потраченных сил? Не проще ли написать это всё более размашисто и менее универсально? Как правило, работа с оборудованием - ничнтожная часть проекта.
|
|
|
|
|
Jun 8 2010, 12:43
|
Участник
  
Группа: Свой
Сообщений: 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-регистры к портам в/в - приемлемое решение.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|