23 янв. 2011 г.

Разрабатываем ядро для компонентов исполнительного уровня "умного дома"-2


С тех пор, как я написал предыдущий пост на эту же тему, в проекте произошли большие изменения, о которых я сейчас и расскажу.
Во-первых, микроконтроллер C8051F930-GQ оказался не таким уж и простым для ручной пайки. Кроме того, расстояние между дорожками для посадочного места микроконтроллера оказалось столь мало, что исключало всякую возможность подрисовать фломастером плохо отпечатавшуюся на плате дорожку (для создания печатной платы я использовал ЛУТ).
Во-вторых, у меня не получилось развести программатор FlashBlaster2 для данного микроконтроллера на одной стороне печатной платы. А делать двухстороннюю мне как-то не хотелось - слишком много мороки с совмещением сторон...

Все вышеперечисленное привело к тому, что я снова перешел к семейству AVR. Для отладочной платы я взял микроконтроллер ATtiny2313 - SPI интерфейс у него есть, а для целей научиться работать с радиомодулем TR24A и написать свой сетевой стек больше и не надо... Правда всего 2 килобайта Flash-памяти как-то смущают, но надеюсь, что простенький сетевой стек я туда запихаю. А если в 2 килобайта влезет что-нибудь тоже простенькое и реализующее сенсорную сеть из подобных отладочных плат, то это будет просто замечательно...

Программаторы для микроконтроллеров AVR от Atmel тоже довольно простые, начиная от 5 проводков на LPT порт, Uniprof'а и прочих... Для себя я спаял Uniprof - схема простая, надежная, работает и под Windows и под Linux.
Uniprof
Чтобы заставить работать этот программатор под Linux'ом с avrdude, нужно прописать следующие строчки в /etc/avrdude.conf:
programmer
id = "nikolaew";
desc = "serial port banging, reset=dtr sck=rts mosi=txd miso=cts";
type = serbb;
reset = 4;
sck = 7;
mosi = 3;
miso = 8;
;
Для проверки связи программатора с МК можно выполнить следующую команду:
avrdude -n -c nikolaew -P /dev/ttyS0 -p t2313
Если все в порядке, то avrdude ответит примерно так:
drag0n@drag0n-desktop:~/Dropbox/docs/Диплом/progs/test4attiny2313$ avrdude -n -c nikolaew -P /dev/ttyS0 -p t2313

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e910a

avrdude: safemode: Fuses OK

avrdude done.  Thank you.
Теперь можно и прошить что-нибудь. Если в процессе записи во Flash avrdude внезапно "зависнет" или если после записи во Flash проверка записанного завершится неудачей, то здесь рекомендуют отпаять проводок от ноги №2 разъема DB-9F. Мне помогло.

Новая схема отладочной платы теперь выглядит так:
Выводы SPI-интерфейса для программирования МК и для общения с TR24A выведены на оловянные контактные площадки. Сначала я хотел подключаться к этим площадкам при помощи "крокодильчиков", но оказалось, что они не обеспечивают должного контакта (убил пару дней в поисках причины отсутствия связи между микроконтроллером и программатором). Лучше всего припаять к этим контактным площадкам проводочки, а уже к ним и подключаться "крокодилами".
Как можно заметить, вывод SS (Slave Select) для SPI не разведен. На корпусе микроконтроллера такая нога отсутствует, что подтверждается и даташитом (раздел про Universal Serial Interface). Думаю, можно на время работы с радиомодулем просто подключать его вывод SS к выводу RESET микроконтроллера - он как раз подтянут резистором к единице.

Мной написана простенькая прошивка для кристалла, которая инициализирует таблицу векторов прерываний, устанавливает указатель на вершину стека и переводит все GPIO порты в режим Output, с подтяжкой к земле. Кстати, с этими выводами связана одна история, чуть было не закончившаяся трагически. Скачал я тестовую прошивку, которая меняла состояние практически всех ног микроконтроллера с 0 на 1 и обратно по таймеру. Прошил ее, светодиод на плате замигал, значит все работает. Но лабораторный блок питания стал показывать какие-то дикие токи в моменты зажигания светодиода - в районе 0.4 ампер, а напряжение проседало аж на половину вольта. Потрогал пальцем кристалл - вроде холодный. Когда же до меня дошло, что при выставлении единички на выводах МК те выводы, которые подтянуты к земле, тупо замыкаются накоротко, микросхема была уже раскаленной. К счастью, все обошлось...
Вернемся к прошивке. Для компиляции я использовал avr-gcc версии 4.5.3. Размер HEX-файла составил всего 214 байт. По данным avr-size программа занимает всего 68 байт памяти программ, что составляет 3.3% процента от всей Flash-памяти ATtiny2313.
avr-size -C --mcu=attiny2313 test4attiny2313.elf
AVR Memory Usage
----------------
Device: attiny2313

Program:      68 bytes (3.3% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

Makefile, которым все компилировалось и прошивалось:
BIN=test4attiny2313

CC=avr-gcc
OBJCP=avr-objcopy
SZ=avr-size
DUDE=avrdude
CFLAGS=-c -pipe -Wall -O0 -mmcu=attiny2313 -msize -mtiny-stack
OBJCPFLAGS=-O ihex
SZFLAGS=-C --mcu=attiny2313
DUDEPORT=/dev/ttyS0
DUDEFLAGS=-c nikolaew -P $(DUDEPORT) -b 1200 -p t2313

ASRC=init.S
CSRC=main.c
SRC=$(ASRC) $(CSRC)
OBJS=init.o main.o

all: hex
    $(SZ) $(SZFLAGS) $(BIN).elf

hex: out
    $(OBJCP) $(OBJCPFLAGS) -R .eeprom -R .fuse \
-R .lock $(BIN).elf $(BIN).hex
    $(OBJCP) $(OBJCPFLAGS) -j .eeprom \
--set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 \
--no-change-warnings $(BIN).elf $(BIN).eep

out: $(SRC)
    $(CC) $(CFLAGS) -Wa,-gstabs $(ASRC)
    $(CC) $(CFLAGS) $(CSRC)
    $(CC) -mmcu=attiny2313 -msize -mtiny-stack \
-Wl,--start-group -nostartfiles -N -Wl,--end-group -o $(BIN).elf $(OBJS)

load: $(BIN).hex $(BIN).eep
    $(DUDE) $(DUDEFLAGS) -U flash:w:$(BIN).hex:i
    $(DUDE) $(DUDEFLAGS) -U eeprom:w:$(BIN).eep:i

clean:
    rm -f $(OBJS) \
        $(BIN).elf \
        $(BIN).hex \
        $(BIN).eep

.PHONY: clean load


init.S:
#include <avr/io.h>

.section .text
.global _start
.global main
.org 0x0000
.align 0

_start:
    ;vector interrupt table
    rjmp reset_handler ;RESET
    rjmp dummy_handler ;INT0
    rjmp dummy_handler ;INT1
    rjmp dummy_handler ;TIMER1 CAPT
    rjmp dummy_handler ;TIMER1 COMPA
    rjmp dummy_handler ;TIMER1 OVF
    rjmp dummy_handler ;TIMER0 OVF
    rjmp dummy_handler ;USART0 RX
    rjmp dummy_handler ;USART0 UDRE
    rjmp dummy_handler ;USART0 TX
    rjmp dummy_handler ;ANALOG COMP
    rjmp dummy_handler ;PCINT
    rjmp dummy_handler ;TIMER1 COMPB
    rjmp dummy_handler ;TIMER0 COMPA
    rjmp dummy_handler ;TIMER0 COMPB
    rjmp dummy_handler ;USI START
    rjmp dummy_handler ;USI OVERFLOW
    rjmp dummy_handler ;EE READY
    rjmp dummy_handler ;WDT OVERFLOW

reset_handler:
    ;setup stack pointer
    ;WARNING! - no SPH in attiny2313!
    ldi r16, RAMEND
    out _SFR_IO_ADDR(SPL), r16
    ;configure pins as output and low
    ser r16
    out _SFR_IO_ADDR(DDRB), r16
    out _SFR_IO_ADDR(DDRD), r16
    clr r16
    out _SFR_IO_ADDR(PORTB), r16
    out _SFR_IO_ADDR(PORTD), r16
    ;jump to main()
    rcall main

dummy_handler:
    rjmp dummy_handler


Ну и main.c:
int main() {
    while (1) {}
    return 0;
}


Исходный код прошивки вместе с самой прошивкой (test4attiny2313.tar.bz2, 2.7 Кб)
Схема программатора Uniprof (сделана в Eagle) и разведенная печатная плата (сделана в TopoR'е) (uniprof.tar.bz2, 128 Кб)
Схема и разведенная печатная плата отладочной платы (actuators_kernel_avr.tar.bz2, 726 Кб)

UPD 25.01.2011: Как выяснилось, ножка SPI_SS все же важна - ею нужно дергать, как прописано в даташите на EM198810AW - это микросхема, стоящая в TR24A. Придется делать новую плату...
UPD2 25.01.2011: SPI интерфейс в ATtiny2313 (USI) поддерживает только SPI mode 0 и SPI mode 1. А для TR24A требуется SPI mode 2 (((. Придется выкинуть и плату и микроконтроллер и сделать/взять другие.

2 комментария:

  1. А каким образом можно создать функцию на Ассемблере с параметрами и выходным значением?
    перерыл все, что только можно, так и не нашел
    Если знаете, напишите, пожалуйста
    pokhvalinv@gmail.com

    ОтветитьУдалить
  2. Просто. Вначале объявляете некую функцию "как обычно" - без параметров и выходного значения. А затем уже самостоятельно организуете обмен параметрами и результатом между вашей функцией и функцией, внутри которой она была вызвана при помощи двух способов:
    1 способ (используемый в том числе и в языке C) - параметры для функции помещаются в регистры процессора, а затем эта функция вызывается. Внутри нее эти параметры читаются из регистров и запоминаются во внутренних переменных, если это необходимо.
    .data
    first_param dw 0x0000
    second_param dw 0x0000
    .code
    main proc
    mov ax, 0xdead
    mov bx, 0xfffa
    call some_func
    endp main
    ;--------
    ;Функция с двумя параметрами,
    ;передаваемыми через регистры
    ;--------
    some_func proc
    mov first_param, ax
    mov secnd_param, bx
    endp some_func
    Аналогично и с выходным значением, только тут вызываемая функция помещает результат в регистр процессора, а вызывающая затем читает его оттуда.

    Второй способ - передавать параметры через стек. Вызывающая функция пихает параметры в стек, а вызываемая вытаскивает их оттуда.
    .data
    first_param dw 0x0fff
    secnd_param dw 0xdead
    .code
    main proc
    push first_param
    push secnd_param
    call some_func
    endp main
    ;---------------
    ;Функция с двумя параметрами,
    ;передаваемыми через стек.
    ;Внутри функции параметры извлекаются из
    ;стека и помещаются в регистры для дальнейшего
    ;использования - первый в ax, второй в bx (не забываем, что
    ;оба параметра по 16 бит.
    ; ---------------
    some_func proc
    pop bx
    pop ax
    endp some_func
    По аналогии и с результатом - вызываемая функция помещает его в стек, а вызывающая вытаскивает его из стека.

    В высокоуровневых ЯП, например в C, все эти действия тоже проделываются при вызове функции с параметрами и возвращаемым значением, но программисту до этого нет дела - компилятор сам вставит необходимые инструкции куда надо.

    ОтветитьУдалить