Ассемблер (ASM) для AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Сообщение dgrett »

[uquote="Alexeyslav",url="/forum/viewtopic.php?p=3557822#p3557822"]Скорей ньюансы со считыванием регистров. Там имеется защёлка, когда один регистр читаешь то пока второй не прочитаешь защёлка не уберётся и новое значение в регистр не попадёт.[/uquote]
Попадёт, не путайте людей.
Я всё-всё узнAю и стану профессором.
Реклама
Мудрый кот
Аватара пользователя
Сообщения: 1812
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

[uquote="МКС",url="/forum/viewtopic.php?p=3557561#p3557561"]ADMUX (ADLAR = 1)

in XH, ADCH
in XL, ADCL[/uquote]
МКС, если вам достаточно 8 старших бит от АЦП, то выровненный в лево результат читайте из старшего регистра АЦП, а младший не трогайте совсем.
При чтении из младшего регистра доступ к регистрам АЦП блокируется пока не прочитаете старший. Т.е. АЦП не сможет поместить новое значение в регистры пока не прочитаете в программе старший регистр!
Поэтому или пользуетесь только старшим регистром или читаете сначала младший, а потом старший.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Встал на лапы
Сообщения: 147
Зарегистрирован: Чт янв 10, 2013 21:03:18

Сообщение МКС »

Alexeyslav, akl, dgrett, Kavka - очень выручили ребята! Все так и было! Проблема исчезла после перестановки порядка считывания регистров (ADCL затем ADCH). Очень благодарен!!!
Мудрый кот
Аватара пользователя
Сообщения: 1812
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Эх, давно это было...
[uquote="Z_h_e",url="/forum/viewtopic.php?p=2898950#p2898950"]Вместо того, чтобы сладко спать, я до сего времени пытался запустить Ваш макрос.[/uquote]Z_h_e, как же я вас понимаю. :) :tea:
[uquote="Z_h_e",url="/forum/viewtopic.php?p=2898950#p2898950"]Данный макрос коварен. :) Если Вы напишите PUSH Я1, то компилятор выдаст ошибку, а если ENTER Я1, то компилятор это проглотит и регистр не будет сохранен. Так что тут проще вляпаться, чем перечислять ПушиПопы.[/uquote][uquote="ARV",url="/forum/viewtopic.php?p=2899099#p2899099"]при наличии таких мощных макросов слабО сделать так, чтобы эта ситуация обрабатывалась? ;)[/uquote]
Слегка :))) модифицированный вариант.
Спойлер

Код: Выделить всё

; -----------------------------------------------
; Авторы: ARV, Z_h_e, Kavka с форума radiokot.ru
; -----------------------------------------------

#include <avr/io.h>

.macro  ENTER   arg:vararg                              ; макрос имеет переменное число параметров
    .set    selector, 0                                 ; в этой переменной будем отмечать нужные регистры
    .set    sel_sreg, 0                                 ; в этой переменной будем отмечать сохранение SREG

; перебераем аргументы и проверяем на допустимость
    .irp    reg,\arg
        .set    ch, 1
        .irp    p, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31
            .if (\p == \reg)                            ; если аргументом макроса совпадает с элементов из списка
                .set    ch, 0
            .endif
        .endr
        .irp    p, R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,R17,R18,R19,R20,R21,R22,R23,R24,R25,R26,R27,R28,R29,R30,R31
            .if (\p == \reg)
                .set    ch, 0
            .endif
        .endr
        .irp    p, xl,xh,yl,yh,zl,zh,sreg,XL,XH,YL,YH,ZL,ZH,SREG
            .if (\p == \reg)
                .set    ch, 0
            .endif
        .endr
        .if ( ch )
            ; ругаемся если аргумент не опознан... :-)
            .print "Error: macro ENTER - unkown register"
            .err
        .endif
    .endr

; перебрать аргументы и отметить их битами в selector
    .irp    reg,\arg
        .set    i, 0
        ; надо перечислить все регистры по порядку!!!
        .irp    p, r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31
            .if (\p == \reg)                            ; если аргументом макроса совпадает с элементов из списка
                .set    selector ,(selector | (1 << i)) ; сделаем отметку в нужном бите
            .endif
            .set    i, i+1                              ; и продолжим счет
        .endr
    .endr
    .irp    reg,\arg
        .set    i, 0
        .irp    p, R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,R17,R18,R19,R20,R21,R22,R23,R24,R25,R26,R27,R28,R29,R30,R31
            .if (\p == \reg)
                .set    selector ,(selector | (1 << i))
            .endif
            .set    i, i+1
        .endr
    .endr

    ; альтернативные названия регистров
    .irp    reg,\arg
        .set    i, 26
        ; надо перечислить все регистры в соответствии с номерами
        .irp    p, XL,XH,YL,YH,ZL,ZH
            .if (\p == \reg)
                .set    selector ,(selector | (1 << i))
            .endif
            .set    i, i+1
        .endr
    .endr
    .irp    reg,\arg
        .set    i, 26
        .irp    p, xl,xh,yl,yh,zl,zh
            .if (\p == \reg)
                .set    selector ,(selector | (1 << i))
            .endif
            .set    i, i+1
        .endr
    .endr

    ; проверяем список аргументов на SREG
    .irp    reg,\arg
        .irp    p, SREG, sreg
            .if (\p == \reg)
                .set    selector ,(selector | 1)        ; сделаем отметку для r0
                .set    sel_sreg ,1                     ; сделаем отметку для SREG
            .endif
        .endr
    .endr

    ; сохраняем регистры
    
    ; сначала r0
    .if (selector & (1))
        push    r0
    .endif

    ; потом SREG
    .if (sel_sreg)
        in      r0, _SFR_IO_ADDR(SREG)                  ; _SFR_IO_ADDR(SREG) - извлекаем адрес порта
        push    r0
    .endif

    ; наконец все остальные, перебрать биты selector от МЛАДШЕГО к старшему и сохранить нужные регистры
    .set    i, 1
    .irp    p, r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31
        .if (selector & (1<< i))
            push    \p
        .endif
        .set    i, i+1
    .endr

.endm


;----------------------------------------
.macro LEAVE
    .set    i, 31
    ; регистры до r1
    .irp    p, r31,r30,r29,r28,r27,r26,r25,r24,r23,r22,r21,r20,r19,r18,r17,r16,r15,r14,r13,r12,r11,r10,r9,r8,r7,r6,r5,r4,r3,r2,r1
        .if selector &(1<< i)
            ; если бит в маске установлен - регистр извлекается из стека
            pop \p
        .endif
        ; перебор битов ведется в обратном порядке!!!
        .set    i, i - 1
    .endr
    .if (sel_sreg)
        pop     r0
        out     _SFR_IO_ADDR(SREG), r0
    .endif
    .if (selector & (1))
        pop     r0
    .endif

.endm


; Например, вот такой исходник

;.global main
;main:
;ENTER r2,r3,SREG,ZH,ZL
;nop
;LEAVE

; Тут нужен препроцесор, т.к. avr-as его не умеет, 
; а определения регистров ввода-вывода прописаны
; в Си-шных заголовочных файлах (привет SREG :-) ).
; С помощью вот таких командочек
; avr-gcc -E -mmcu=atmega48 gnu-as_macros.S | avr-as -mmcu=atmega48 - 
; avr-objdump -d a.out
; Получим вот такой код

;00000000 <main>:
;   0:   0f 92           push    r0
;   2:   0f b6           in      r0, 0x3f        ; 63
;   4:   0f 92           push    r0
;   6:   2f 92           push    r2
;   8:   3f 92           push    r3
;   a:   ef 93           push    r30
;   c:   ff 93           push    r31
;   e:   00 00           nop
;  10:   ff 91           pop     r31
;  12:   ef 91           pop     r30
;  14:   3f 90           pop     r3
;  16:   2f 90           pop     r2
;  18:   0f 90           pop     r0
;  1a:   0f be           out     0x3f, r0        ; 63
;  1c:   0f 90           pop     r0


Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Сообщения: 5066
Зарегистрирован: Вс фев 15, 2009 01:04:58
Откуда: Kaluga

Сообщение Wladimir_TS »

Что-то крепко торможу - поясните пожалуйста.

AVR MEGA использую таймер 1 в режиме WGM10 =1, WGM11 =0, WGM12 =0, WGM13 =1

От скольких и до скольких считает собственно таймер и в какой момент обновляется позиция по которой переключается ШИМ выход ? Не момент переключения выхода а момент с которого число для сравнения, загруженное в OCR1A(B) будет актуально. При каком значении таймера. (предполагаю что 0)

А второй вопрос - вот такой код : (Ячейка может содержать значения 1-4), R1=0, P1-P4 - метки на некие программные действия, ВЫХОД - ничего не делать как вообще работает и зачем он такой сложный...

lds r24, Ячейка
lds r25, Ячейка


cpi r24, 2
cpc r25, R1
breq P2
cpi r24, 3
cpc r25, R1
brcc P3
sbiw r24, 1
brne ВЫХОД
rjmp P1

P3:
cpi r24, 3
cpc r25, R1
breq P4

sbiw r24, 4
brne ВЫХОД
Реклама
akl
Друг Кота
Сообщения: 4473
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

В DS на меги явно указано когда для режима 9 идет занесение. За счет буфера можно заносить не заботясь о глюках. Актуальное значение в OCR1A будет выполнено в следующих, после переноса циклах.
СпойлерИзображение
Вложения
M8515_COMP9.PNG
(76.06 КБ) 429 скачиваний
Реклама
Друг Кота
Сообщения: 5066
Зарегистрирован: Вс фев 15, 2009 01:04:58
Откуда: Kaluga

Сообщение Wladimir_TS »

А величина этого BOTTOM чем определяется - так как похоже не до 65535 считает и по коду вопрос стоит.
akl
Друг Кота
Сообщения: 4473
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Там же в DS
BOTTOM Signalize that TCNTn has reached minimum value (zero).
По коду. Херь какая-то.
Встал на лапы
Сообщения: 147
Зарегистрирован: Чт янв 10, 2013 21:03:18

Сообщение МКС »

Подскажите, как правильно организовать спящий режим во время работы АЦП в ATmega8 и самое главное как из него выйти сразу же после окончания однократного преобразования? Вот фрагмент программы:
main:
/
/ ; выполняется программа
/
/

sleep ; здесь надо заснуть, что-бы работе АЦП ничего не мешало

ldi R16, 0b00000000
out ADMUX, R16
ldi R16, 0b11001100
out ADCSRA, R16
; здесь надо проснуться
in XL, ADCL
in XH, ADCH
mov R17, XL
mov R18, XH

sleep ; здесь надо опять заснуть, что-бы работе АЦП ничего не мешало

m7: ldi R16, 0b00000000
out ADMUX, R16
ldi R16, 0b11001100
out ADCSRA, R16
; здесь надо опять проснуться
in XL, ADCL
in XH, ADCH

cp XL, R17
cpc XH, R18
brne main

cp XL, YL
cpc XH, YH

breq main
brlo m3

rcall vpravo
rjmp main

m3: rcall vlevo
rjmp main
akl
Друг Кота
Сообщения: 4473
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Как вариант
Спойлер

Код: Выделить всё

;
.include "m8def.inc"

.cseg
.org 0

;ВЕКТОР ПРЕРЫВАНИЙ
RESET:
	rjmp initial

.org 0x0E
ADC_COMPLETE:
	in XL, ADCL
	in XH, ADCH

	RET
;*************************************************
initial:
	CLI
	ldi R16,low(RAMEND)
	out SPL,R16
	ldi R16,high(RAMEND)
	out SPH,R16
GO:
	LDI	R16,1<<SE|1<<SM2	; ADC NOISE
	OUT	MCUCR,R16

	ldi R16, 0b00000000
	out ADMUX, R16

main:
	LDI R16,1<<ADEN|1<<ADSC|1<<ADIE|1<<ADIF|1<<ADPS2 ;/16
	OUT ADCSRA, R16

	SEI
	sleep ; здесь надо заснуть, что-бы работе АЦП ничего не мешало
;	NOP

;ldi R16, 0b00000000
;out ADMUX, R16
;ldi R16, 0b11001100
;out ADCSRA, R16
; здесь надо проснуться
;	in XL, ADCL
;	in XH, ADCH
	mov R17, XL
	mov R18, XH

	SBI	ADCSRA,ADSC

	SEI
	sleep ; здесь надо опять заснуть, что-бы работе АЦП ничего не мешало
;	NOP

m7:
; ldi R16, 0b00000000
;out ADMUX, R16
;ldi R16, 0b11001100
;out ADCSRA, R16
; здесь надо опять проснуться
;in XL, ADCL
;in XH, ADCH

	cp XL, R17
	cpc XH, R18
	brne GO

	cp XL, YL
	cpc XH, YH

	breq GO
	brlo m3

	rcall vpravo
	rjmp GO

m3:
	rcall vlevo
	rjmp GO

VPRAVO:
	RET
VLEVO:
	RET
.EXIT
Модератор
Аватара пользователя
Сообщения: 19101
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

интересно, а что может мешать работе АЦП?
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Встал на лапы
Сообщения: 147
Зарегистрирован: Чт янв 10, 2013 21:03:18

Сообщение МКС »

У меня в двух младших битах числа нестабильно фиксируются. Прочитал, что это может быть результат помехи от АЛУ и др. периферии
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Сначала проверьте качество разводки AGND, фильтрацию AVCC потом уже АЛУ...
Контактная информация:
Встал на лапы
Сообщения: 147
Зарегистрирован: Чт янв 10, 2013 21:03:18

Сообщение МКС »

Согласен. Я проверяю программу на самодельном отладочном устройстве, где на выводы AVcc и AREF соединены вместе и подключены к +5V через дроссель 10 мкГн. К обоим концам дросселя подпаяны конденсаторы по 0,1 мкФ на общий вывод. А вот печатная плата отладчика односторонняя и дорожки с подводом питания к АЦП относительно длинные. Сейчас делаю печатную плату из двухстороннего фольгированного стеклотекстолита с другой разводкой дорожек (более короткой длиной) Верхний слой фольги печатной платы оставлю в качестве экрана.
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич

Сообщение Alexeyslav »

Просто соблюдения схемы ещё ндостаточно, нужно соблюсти ещё и топологию на плате. Так чтобы по AGND проводу не шли цифровые токи. На дорожке даже в 1мм шириной миливольты набираются только так!
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

[uquote="МКС",url="/forum/viewtopic.php?p=3560981#p3560981"]У меня в двух младших битах числа нестабильно фиксируются...[/uquote]
Из даташита:
±2 LSB Absolute Accuracy
Docendo discimus
Контактная информация:
Мучитель микросхем
Аватара пользователя
Сообщения: 473
Зарегистрирован: Ср янв 11, 2012 18:20:26

Сообщение shonty »

[uquote="МКС",url="/forum/viewtopic.php?p=3560981#p3560981"]У меня в двух младших битах числа нестабильно фиксируются.[/uquote]
Недавно тоже испытал такое. Помогла установка после некоторых команд небольших (10мсек) задержек или просто nop-ов.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

shonty писал(а):Помогла установка после некоторых команд небольших (10мсек) задержек или просто nop-ов
если "мсек" это МИЛЛИсекунды, то 10 - это очень много! это очень большая задержка по МК-шным меркам. и тут явно что-то не так в схемотехнике, раз нестабильность показаний лечится таким способом...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
akl
Друг Кота
Сообщения: 4473
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Для повышения стабильности значений АЦП сделан специальный режим сна
ADC Noise Reduction
, когда тактирование ядра, портов ввода-вывода останавливается и обслуживаются только разрешенные прерывания.
СпойлерИзображение
Вложения
ADC_NOISE.PNG
(66.23 КБ) 488 скачиваний
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

[uquote="МКС",url="/forum/viewtopic.php?p=3560981#p3560981"]...нестабильно фиксируются...[/uquote]
Определиться бы для начала - насколько точные значения нужны? Для чего?
Docendo discimus
Контактная информация:
Ответить

Вернуться в «AVR»