Наконец то я добрался и до линуксовых драйверов, герой сегодняшнего обзора i2c микросхема матричной клавиатуры.

Досталась мне микросхемка max7370 и нужно было ее запустить под linux, чтобы полноценно работала кастомная матричная клавиатура. Если глубоко поковыряться в исходниках ядра, то можно найти готовый драйвер max7359, насколько я понял это упрощенный аналог 7370. В общем было время, было желание, поэтому решил запилить свой велосипед, заодно разобраться с линуксовой i2c подсистемой.

На самом деле, если смотреть глобально то там все просто, однако есть небольшие особенности, про которые очень мало информации. Именно поэтому решил запилить свое. Итак, вернемся к железу. Сама микросхемка малюсенькая.
max7370_matrix

Как видно, для лута не подойдет) Ставить ли ее для микроконтроллеров это большой вопрос, ибо современные стмки довольно жирные, поэтому нужно исходить из ситуации. Однако в мире одноплатников однозначно да.

У данной микросхемы много ништяков, ее можно использовать как расширитель портов, еще ноги можно регулировать ШИМом. Так как устройство было постоянно подключено к сети, поэтому автосон оказался не нужен, автоповторы нажатия кнопок тоже оказались не задействованы и т.п. В моем случае требовался только базовый функционал, т.е. только опрос кнопок. Возможно чуть позже добавлю информацию по остальному.

Пройдемся по основным регистрам, которые использовал в своем драйвере.

Register 0: Keys Fifo, т.е. буфер содержащий последние нажатия кнопок, т.е. по сути для нас это и есть коды нажатых клавиш. Если нажатых кнопок нет, то возвращает 0x3F

Register 1: Configuration, настройки. Из интересного тут 3бит KEY_RELEASE, включение/выключение отпускания кнопки, 5бит — настройка прерывания, влияет на то когда ножка прерывания INT подымется. 0 — когда фифо пустой, т.е. пока все значения клавиш не будут прочитаны, нога прерывания будет висеть в нуле. 1 — достаточно один раз прочитать буфер и нога подымется. По сути читать фифо нужно и в том и другом случае, какой случай использовать зависит от конкретной задачи. Бит 7 — вход/выход из сна. По дефолту контроллер спит.

Key-Switch Debounce Register (0x02). Настройки антидребезга, 4бита на нажатие кнопки, 4бита на отпускание. 1бит = 2мс, т.е. суммарно от 2 до 32мс.

Key-Switch Interrupt Register (0x03). Настройка частоты срабатывания прерывания, для того чтобы не перегружать проц прерываниями. Можно настроить либо по срабатыванию от FIFO, или от времени, или оба сразу.

Key-Switch Array Size Register (0x30). Размер сканируемой матрицы. Тут можно настроить ноги для сканирования кнопок.

Собственно остальные фичи рассмотрю чуть позже. Схема подключения вроде понятная, комментировать особо нечего, к процу заводим 2 ноги i2c и ногу прерывания, которая срабатывает при появлении новых данных. Клавиатуру подключать к col, row, т.е. столбцы строки.
max7370

Протокольный уровень стандартный: шлем адрес микросхемы, шлем номер регистра и данные, все просто. Читаем точно также.

Теперь непосредственно по драйверу. Комментировать все целиком смысла не имеет, поэтому пробегусь по основным моментам. Выходим из сна, включаем прерывание и нажатие клавиш. Настраиваем прерывание по времени. Выключаем автосон. Устанавливаем размер матрицы на полную.

static void max7370_initialize(struct i2c_client *client) {
 
        /* disable sleep, enable key release, clear int on first read */
	max7370_write_reg(client, 
	        MAX7370_REG_CONFIG, MAX7370_CFG_KEY_NORELEASE | MAX7370_CFG_INTERRUPT | MAX7370_CFG_WAKEUP); 
 
	/* debounce time 16ms */
	max7370_write_reg(client, MAX7370_REG_DEBOUNCE, 0x77);
 
	/* nINT asserts every debounce cycles */
	max7370_write_reg(client, MAX7370_REG_INTERRUPT, 0x01);
 
	/* disable Autosleep  */
	max7370_write_reg(client, MAX7370_REG_SLEEP, MAX7370_AUTOSLEEP_DISABLE);
 
	/* kb arr size */
	max7370_write_reg(client, MAX7370_REG_ARR_SIZE, 0xFF); 
}

Внутри __init задаем ногу прерывания, особенно заставила попотеть установка прерывания. Вначале я пытался повесить опрос микросхемы внутри обычного прерывания от ноги, из за этого система падала, поэтому правильно запускать опрос в отдельном потоке devm_request_threaded_irq.

max_i2c_adap = i2c_get_adapter(KB_I2C); 

Позволяет получить физический адрес i2c адаптера по номеру шины i2c.

max7370_client = i2c_new_dummy (max_i2c_adap, KB_ADDR);

Заполняем структуру i2c_client, номером адаптера и адресом.

Собственно, про input_device распишу в другой раз подробнее, так как тут есть о чем рассказать. А вот про read_dts_pins, пожалуй стоит подробнее рассмотреть. Итак, dts это такой файлик, в котором содержится описание различных устройств, которые аппаратно зависимые.

Если рассматривать совсем утрированно, то это просто файл, в котором вы можете написать что угодно. Но таки назначение его именно в том, чтобы задать некий параметр и его значение. Предположим у вас есть некий дефайн и чтобы каждый раз не перекомпилировать драйвер, вы задаете в dts этот дефайн, а драйвер читает ваше значение при запуске.

На самом деле, тут тоже есть свои особенности dts тоже надо компилить в dtb, ибо ядро обращается именно к нему, т.е. dts исходник, а dtb — бинарь. Есть еще особенности, ибо все таки писать можно не все что угодно, но единой годной документации и четких правил я пока не нашел. Вообще штука очень мощная, поэтому потихоньку буду добавлять инфу.

Итак, вернемся к драйверу. В dts прописываем такую штуку:

max7370: max7370@38{
		 compatible = "mx,max7370";
		 max7370_addr = <0x38>;
		 max7370_irq_pin = <117>;
		 max7370_bus_n = <1>;
		 max7370_keycodemax = <0xff>;
		 max7370_dbg_en = <0>;
		 max7370_keycodes = <48 10 7 4 11 9 6 3 30 8 5 2 >;
		 max7370_scancodes = <0 1 2 3 8 9 10 11 16 17 18 19>;		 
    };

Сам девайс и его адрес на шине max7370@38. max7370_addr — адрес устройства, max7370_irq_pin — номер ножки прерывания. max7370_bus_n номер шины устройства. max7370_keycodemax — максимальный код клавиши, чтобы не перебирать всю клавиатуру. max7370_dbg_en — включение отладки, если включено, то в консоль будут падать сканкоды фифо буфера. max7370_keycodes используемые клавиши клавиатуры, max7370_scancodes — используемые сканкоды фифо буфера.

Вообще, dts штука довольно хитрая, не смотря на простоту в ней много премудростей, поэтому не исключаю что есть пути задания keycode и scancode проще.

Итак, если подытожить. Микросхема годная, если нужно к одноплатнику подключить матричную клаву, то вполне сгодится. Пилить драйвера такого уровня не сложно, по сути если человек работал с настройкой периферии для микроконтроллера то ничего нового. Конечно есть особенности, хуже всего, на мой взгляд, это отсутствие хорошей документации. Однако, спасает ситуацию большое количество написанного кода, очень много всего полезного можно откопать в исходниках ядра. Кроме того, в целом все написано понятно. Исходнички можно забрать на GITHUB

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Свежие записи
Последние комментарии
  • Загрузка...
Архивы
Счетчик
Яндекс.Метрика