Аппаратные порты ввода/вывода

From NutWiki

Jump to: navigation, search

Contents

Аппаратные порты

Аппаратные порты (например цифровые или аналоговые I/O, RS232 и т.д.) как правило, управляются специальными регистрами. Например, большинство процессоров, используемых в системах как правило имеют встроенные двунаправленные цифровые порты ввода / вывода управляемые набором регистров.

  • Port direction register
    Каждый бит в этом регистре устанавливает, используется соответствующий вывод порта в качестве входа или выхода.
  • Port output register
    If the corresponding bit in the port direction register is set to output, then the bit value in this register will directly set the port pin. If the bit is zero, the related output pin will be driven low. If the bit is set to one, then the pin will be driven high.
  • Port input register
    If the corresponding bit in the port direction register is set to input, then this register will reflect the current status at the related pin. If the signal level at the pin is low (e.g. tied to ground), the corresponding bit will be zero. If the level passes a certain voltage, then the bit in this register will change to one.

Depending on the CPU, hardware I/O port registers may be accessed like any other memory location. This is called memory mapped I/O. Some CPUs, most notably Intel's x86 series, offer a dedicated I/O bus, which is seperated from the memory bus. In this case the hardware registers are port mapped and specific CPU instructions like inp (read port) or outp (write port) must be used to access them. Although all CPUs currently supported by Nut/OS provide memory mapped I/O, specific C language macros for port access are preferred in order to hide this difference. These macros can be easily adapted to both, memory mapped and port mapped hardware. Furthermore, it is easier to get applications running in an emulator, if access to I/O registers is distinguishable from access to memory locations.

Размерность регистров.

Beside differing access methods, CPUs provide different register sizes. Typically, 8-bit machines use 8-bit I/O registers while 32-bit machines use 32-bit I/O registers. Nevertheless, while 8-bit hardware may use 16 or 32 bit registers, almost all 32-bit CPUs are able to access registers with 16 or 8 bits in size. Thus, a number of macros for different register sizes is provided. The Nut/OS macros inr() and outr() provide access to the CPU specific register size (missing on 8-bit targets).

Макросы доступа к портам в Nut/OS.

Размер регистра Тип переменной Макрос вывода Макрос ввода
8 Бит unsigned char outb(регистр/порт, значение) inb(регистр/порт)
16 Бит unsigned short outw(регистр/порт, значение) inw(регистр/порт)
Определяется типом CPU
8, 16 или 32 Бит
unsigned int outr(регистр/порт, значение) inr(регистр/порт)


Использование цифровых портов ввода/вывода в AVR.

Чтение данных цифрового порта состоит из 2 шагов.

  1. Установка необходимого регистра порта в режим ввода.
  2. Чтение данных порта ввода.

Пример чтения значений всех 8 битов порта PORTB.

 #include <compiler.h> /* Совместимость платформ. */
 unsigned char val;
 outb(DDRB, 0x00); /* Установить все 8 битов порта PORTB для ввода.*/
 val = inb(PINB);  /* Чтение значений всех 8 битов порта PORTB в переменную.*/

Запись данных в цифровой порт состоит из 2 шагов.

  1. Установка необходимого регистра порта в режим вывода.
  2. Запись данных в порт.

Пример записи значений всех 8 битов порта PORTB .

 #include <compiler.h>
 outb(DDRB,0xFF);  /* Установка регистра порта PORTB для вывода.*/
 outb(PORTB,0x00); /* Установка всех битов порта PORTB в низкое (0000 0000).*/
 outb(PORTB,0xFF); /* Установка всех битов порта PORTB в высокое (1111 1111)*/

Using Digital I/O on AT91 ARM

Here's how to read the level at the 8 least significant bits of the digital I/O port on the AT91R40008 CPU.

#include <compiler.h> /* Provides compatibility among platforms. */
unsigned int val;
outr(PIO_ODR, 0xFF); /* Use lower 8 bits for input. */
outr(PIO_PER, 0xFF); /* Enable PIO function. */
val = inr(PIO_PDSR); /* Read pin status. */

For digital output, a sightly different method is used on Atmel's AT91 series. Different registers are provided to set and clear the bits. In other word, there is a specific register for setting a digital output to high and another one to set the output to low.

#include <compiler.h>

outr(PIO_OER, 0xFF);  /* Use lower 8 bits for input. */
outr(PIO_PER, 0xFF);  /* Enable PIO function. */
outr(PIO_CODR, 0xFF); /* Set bits to low. */
outr(PIO_SODR, 0xFF); /* Set bits to high. */

"Родные" команды доступа к портам ввода/вывода AVR

При просмотре примеров AVR не для Nut/OS, Вы, возможно, обратили внимание, что нет никаких определенных макросов ввода и вывода. Большинство компиляторов для AVR позволяют использовать порты ввода - вывода как переменные C. К примеру, установка четырех старших бит порта PORTB на вывод и установка четыре младших бита для ввода может быть записана так

 /* Пример 1 */
 DDRB = 0xF0;
 /* В следующем строке кода показано изменение значения первого бита из четырех старших бит порта */
 /* PORTB на 1, остальные остаются неизмененными. */
 /* значение до операции с портом -> 0000 0000*/
 PORTB |= 0x10; /* PORTB = PORTB | 0b00010000*/
 /* значение после -> 0001 0000*/

Данный метод вы можете применять в своих приложениях для Nut/OS. Однако этот путь доступа к портам не полностью машинонезависимый, и поэтому в Nut/OS предпочтительней использовать макросы ввода и вывода, вот так

 /* Пример 2 */
 outb(DDRB, 0xF0);
 outb(PORTB, inb(PORTB) | 0x10);

Однако, второй пример не может быть точно оттранслирован в тех же самых машинных инструкциях как в примере 1,в котором PORTB используется как переменная C. Поэтому на определенных портах CPU в состоянии изменить отдельные биты одной командой. Использование inb() и outb() заставляет компилятор генерировать три машинные инструкции.

  1. Чтение байта из порта PORTB
  2. Установка 4 бита в единицу
  3. Запись байта обратно в порт PORTB

Для разрешения данной проблемы в Nut/OS существуют два дополнительных макроса для установки либо очистки одиночного бита. Установка и сброс 4 бита порта PORTB может быть записана так

 sbi(PORTB, 4);/* Установка 4 бита в 1 */
 сbi(PORTB, 4);/* Установка 4 бита в 0 */

Native AT91 ARM I/O Register Access

Developers, which are familiar with the header files provided by Atmel for I/O register access will miss the register structure definitions. They are most convenient and produce highly readable code. However, they are not fully portable, very difficult or impossible to emulate and they can't be included into low level assembler code. Although not recommended, you can use these header files in your Nut/OS applications. [edit] Возможные ошибки. No Input Change on AVR Make sure you use inb(PINB), not inb(PORTB). The latter doesn't query the status of the input pin, but of its pull-up resistor. [edit] 16 Bit Register Access Fails on AVR If two 8-bit accesses work while a single 16-bit access fails, then the register you are using requires a different order. The 16 bit outw() and inw() macros write or read the low byte first, followed by the high byte. This may not work on all registers, specifically with AVR timers/counters. [edit] No Input Change on ARM Most ARM CPUs require to enable the PIO clock in order to latch input pins. This may be even true for output pins.

Возможные ошибки(ловушки)

No Input Change on AVR

Make sure you use inb(PINB), not inb(PORTB). The latter doesn't query the status of the input pin, but of its pull-up resistor.

16 Bit Register Access Fails on AVR

If two 8-bit accesses work while a single 16-bit access fails, then the register you are using requires a different order. The 16 bit outw() and inw() macros write or read the low byte first, followed by the high byte. This may not work on all registers, specifically with AVR timers/counters.

No Input Change on ARM

Most ARM CPUs require to enable the PIO clock in order to latch input pins. This may be even true for output pins.

See also

Personal tools