воскресенье, 29 ноября 2009 г.

Пишем драйвер для лампочки=) Часть 1.

Хочу описать собственную идею (возможно она не нова), по которой я собираюсь создавать драйверы для различных аппаратных модулей, микросхем и тп.. Базируется она на основе использования статических библиотек, которые будут подключаться к основному проекту и представлять собой драйвер для какого-нибудь отдельно взятого модуля. Статическую библиотеку предлагаю писать на ассемблере, с целью сокращения объёма кода а также получения наивысшей производительности=) Такая библиотека, подключённая к основному проекту будет занимать минимум, при этом останется больше свободного места в памяти МК для написания основной логики.

В качестве примера можно рассмотреть тривиальный пример - драйвер для лампочки (индикатора). Данный пример подходит только для демонстрации самой идеи, а не её практического применения. Лампочка уж слишком простая вещь чтобы для неё писать целый драйвер. А вообще хотелось бы написать таковые для ЖК-дисплея, микросхемы ds1307, да много чего можно ещё придумать:) Главное желание, и свободное время. С последним у меня пока проблемы... Итак, приступим!

Подготовительная часть
1) Необходимо установить в систему пакеты gcc-avr, binutils-avr, и avr-libc. (если ещё не были установлены)
2) Вкратце изучить документацию по avr-libc. Там содержится очень много интересного(:
3) Создать папку для основного проекта, у меня это ~/hard_project.
4) Создать папку для проекта библиотеки, у меня это ~/hard_project/libdrv.

Написание библиотеки
Основной файл будет иметь следующее содержание:
;; файл ~/hard_project/libdrv/leddrv.S:
#include <avr/io.h>
#include "conf.h"

.global led_init ; void led_init()
; предварительная настройка порта
led_init:
  sbi _SFR_IO_ADDR(LED_DDR),LED_NPIN ; установить ножку на вывод данных
  ret

.global led_on ; void led_on()
; включение лампочки
led_on:
  sbi _SFR_IO_ADDR(LED_PORT),LED_NPIN ; записать логическую 1 в порт
  ret

.global led_off ; void led_off()
; выключение лампочки
led_off:
  cbi _SFR_IO_ADDR(LED_PORT),LED_NPIN ; записать логический 0 в порт
  ret

.global led_blink ; void led_blink(uint16_t f)
; мигание лампочки с заданной частотой
led_blink:
  sbi _SFR_IO_ADDR(LED_PORT),LED_NPIN ; записать логическую 1 в порт
  push r24
  push r25
  rcall delay ; задержать выполнение
  cbi _SFR_IO_ADDR(LED_PORT),LED_NPIN ; записать логический 0 в порт
  pop r25
  pop r24
  rcall delay ; задержать выполнение
  ret

; задержка на заданное значение
delay: ; до 770*65535/F_CPU, сек
   clr r0
0: com r0
1: dec r0
    brne 1b
    sbiw r24,1
    brne 0b ; 770 тактов за цикл
    ret

Здесь первый параметр для функции led_blink будет передаваться через регистр r24:r25, согласно соглашениям компилятора avr-gcc. Далее, заголовочный файл будет иметь следующее содержание:
// файл ~/hard_project/libdrv/leddrv.h:
#include <stdint.h>
#ifdef F_CPU
#define led_blink_ms(x) led_blink(((x)*(uint64_t)F_CPU)/(770*1000ul))
#endif

void led_init();
void led_on();
void led_off();
void led_blink(uint16_t f);

Здесь определён макрос led_blink_ms для удобства. При его вызове нужно указывать значение в миллисекундах, в отличии от led_blink, в которой указывается значение в условных единицах =) Последний файл проекта будет иметь следующее содержание:
// файл ~/hard_project/libdrv/conf.h:
#define LED_PORT PORTC
#define LED_DDR  DDRC
#define LED_NPIN PC1

Ну здесь наверное понятно, указываются параметры порта и ножки на которой будет сидеть лампочка =)

Это всё. Теперь необходимо собрать нашу бибиотеку. Упрощённую версию Makefile для сборки проекта можно скачать тут. Скомандовав в консоли, я и получил целевой файл libleddrv.a:
$Make
avr-gcc -Wall -x assembler-with-cpp -mmcu=atmega168 -o .leddrv.o -c leddrv.S
avr-ar rcs libleddrv.a .leddrv.o

В следующий раз я покажу как использовал эту библиотеку в своём проекте=)

---
Скачать исходники libdrv.tar.gz

1 комментарий:

Alexandr комментирует...

Ссылки на загрузку недействительны...перезалей пожалуйста ещё раз.