i2c (slave) расширитель на ATMega

AVR
Потребовалось тут из основной задачи на ARM-e под Linux дрыгоножество неспешное, а ног под GPIO сконфигурировано всего 3 шт! Разумеется, можно пересобрать ядро соответствующим образом, но поскольку в данном вопросе пока слаб, решил поставить расширитель i2c. Когда понял, что в городе я микросхем не найду, и посмотрел цены — понял, что ATMega весьма неплохое решение в данном случае! Попутно выяснил параметры для AVRDUDE, чтобы шить через Arduino бутлоадер.
Очень сильно помог этот материал в разборках с TWI, он же «квадратная шина» i2c.
Возникла заминка — как получить доступ не только регистрам PORTB, но и к остальным, а в идеале — ко всей периферии? Если делать в лоб — сравнивать адрес, потом обратиться к нужному регистру — много кода, ненаглядно, и никакой гибкости. Подумал, поспрашивал на форумах — на местном камрады почти готовое решение дали — используем указатель, значение которого вычисляется, и уже через него читаем-пишем в нужный порт.
В общем, кому надо — пользуйтесь. Мега прикидывается 24cXX, адресация начинается с PINB, дальше — по даташиту. Кому хочется адресации по даташиту — поправьте строку
#define BASEPORT PORTB-2

на такую:
#define BASEPORT PORTB-5

В этом случае адреса будут соответствовать описанию от Atmel.
Ещё момент — не уверен, что будет доступна периферия в верхних адресах, например — UART.
Скриншот терминала с проверкой ниже.

i2c-tools
  • 0
  • 20 августа 2013, 06:47
  • Hoksmur
  • 1
Файлы в топике: i2c_extender.tar.gz

Комментарии (5)

RSS свернуть / развернуть
Лучше использовать макрос _SFR_IO8, который используется в заголовочниках для объявления регистров:
...
data = _SFR_IO8(addr);
...
_SFR_IO8(addr) = data;
...
Но для доступа ко всем регистрам нужно передавать в устройство полный 16-разрядный адрес.
0
  • avatar
  • Resp
  • 20 августа 2013, 10:08
Пробовал, не пошло. Может, конечно, я что не так делал. Но, imho — там адрес должен быть известен на этапе компиляции (при сборке кода), а у меня вычисляется во время выполнения.
0
Хм, странно… У меня работает и с переменной адреса (Мега32):
typedef struct HID_DATA
{
    uint8_t command;
    uint16_t addr;
    uint8_t data;
} hid_data_t;

...

case COMMAND_READ_SFR:
    hid_data.data = _SFR_IO8(hid_data.addr);
    hid_data.command |= COMMAND_RESPONSE;
    break;

case COMMAND_WRITE_SFR:
    _SFR_IO8(hid_data.addr) = hid_data.data;
    hid_data.command |= COMMAND_RESPONSE;
    break;
+1
А, так тут отдельная переменная заведена, тоже играет роль.
Я не хотел делать подобного такому:
a = base; // при каждом обращении
a = a+offset;
// дальше через неё

Я не хочу сказать что плохо, но мне не понравилось. Хотя, если посмотреть при компиляции — то может рекомендуемый способ и меньший по размеру код даст.
0
а я расширители с и2ц и спи заказал нахаляву в микрочипе
и стоят они бакса 1.5

не знаю, как там сейчас, но 10 лет назад собрать ядро под х86 было не очень сложно, но долго
кажется на втором пентиуме 400мгц это занимало час или 3
зато монолитное ядро с нужными драйверами работало очень быстро

под мои роутеры от авм прошивка собирается при помощи графического конфигуратора, где можно так же включить модули и2ц и спи или эмуляцию через гпио на светодиодах
надо просто отметить эти модули и собрать все с нуля
обычно с 3-5 попытки все работает

а писать такую прошивку я бы запарился наверное
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.