Обсуждаем контроллеры компании Atmel.
Ответить

Прошу помощи в поиске ошибки кода Atmega8

Пт июн 22, 2018 10:37:14

Помогите пожалуйста. 3 дня ковыряюсь в прошивке для МК Atmega8A. В Atmel Studio все нормально, пошагово проходит всю программу как положено, со всеми реакциями. Схема планировалась как таймер задержки с реакцией на кнопку при каждом нажатии в течении 7 сек. Если в течении 7 сек кнопка не нажималась то потом отсчитывает 1, 2, 3-6 часов ( в зависимости сколько раз была нажата кнопка). Сделано для часового кварца. Загоняю прошивку в МК реакция на кнопку есть 7 сек отсчитывает, а потом все слетает и похоже срывается в бесконечный цикл. Замучался уже ковыряться, ткните пож. в ошибку.

Вот сама прошивка.

; Taimer_zaderjki.asm
;
; Created: 04.06.2018 11:58:36
; Author : Kiril
;
;start:
; inc r16
; rjmp start

;
; Amega8.asm
;
.include "m8adef.inc" ; открыть файл описаний

.cseg
.org 0
; ++++++++++++++++++++++++++++++++++++переопределение векторов прерываний

rjmp reset ;вектора прерываний
nop ;rjmp INT0;External Interrupt Request 0
nop; rjmp INT1; External Interrupt Request 1
rjmp zdjk; OC2; Timer/Counter2 Compare Match
nop ;rjmp OVF; Timer/Counter2 Overflow
nop ;rjmp ICP1; Timer/Counter1 Capture Event
rjmp zdjk; OC1A; Timer/Counter1 Compare Match A
nop ;stop2; OC1B; Timer/Counter1 Compare Match B;
nop; OVF1; Timer/Counter1 Overflow
nop ;rjmp OVF0; Timer/Counter0 Overflow
nop ;rjmp SPI; Serial Transfer Complete
nop ;rjmp URXC; USART, Rx Complete
nop ;rjmp UDRE; USART Data Register Empty
nop ;rjmp UTXC; USART, Tx Complete
nop ;rjmp ADCC; ADC Conversion Complete
nop ;rjmp ERDY; EEPROM Ready
nop ;rjmp ACI; Analog Comparator
nop ;rjmp TWI; 2-wire Serial Interface
nop ;rjmp SPMR; Store Program Memory Ready

reti

; +++++++++++++++++++++++++++++инициализация стека ++++++++++++++++++++++++++++

reset: ldi r16,high(ramend)
out sph,r16
ldi r16,low(ramend)
out spl,r16

ldi r17,0b11111111;
out portb,r17;
out ddrd,r17;

ldi r17,0b00000001;
out ddrb,r17;

ldi r17,0b00000000;
.equ ddel=255 ;


; ++++++++++++++++++++++++++++++++++++= начало циклов проверки сост кнопок замыкающихся на 0


.def rin=r18;
.def loop=r25
; ldi rin,0b11111111;
nop

ldi r20,0b00000000

ldi r19,0b00000101;
out tccr1b,r19;
ldi r19,0b00000000;
out tccr1a,r19;
ldi r19,0b00000111;
out tccr2,r19;
;
; ++++++++++++++++++++++++++++++++ проверка сост кнопки
;
sw: ldi r19,0b00000001 ;
out portd,r19 ;

; первое нажат кнопки

in rin,pinb;
sbrc rin,1;
rjmp sw;
rcall wait ;
ldi r19,0b00000010 ;
out portd,r19 ;
ldi r22,1;
rcall j1 ;
rcall z7 ;

; второе нажатие кнопки

rcall wait ;
ldi r19,0b00000100 ;
out portd,r19 ;
ldi r22,2;
rcall j1 ;
rcall z7 ;


; третье нажатие кнопки

rcall wait ;
ldi r19,0b00001000 ;
out portd,r19 ;
ldi r22,3;
rcall j1
rcall z7


; четвертое нажатие кнопки

rcall wait
ldi r19,0b00010000 ;
out portd,r19 ;
ldi r22,4;
rcall j1 ;
rcall z7 ;

; пятое нажатие кнопки

rcall wait ;
ldi r19,0b00100000 ;
out portd,r19 ;
ldi r22,5;
rcall j1 ;
rcall z7 ;


; шестое нажатие кнопки

rcall wait ;
ldi r19,0b00001000 ;
out portd,r19 ;
ldi r22,6;
rcall j1 ;
rcall z7 ;

rjmp sw;



; определение отсчета 30 мин

schet: ; ++++++++++++++++++++++++++++ определение маски прерывания ++++++++++++++++++
ldi r20,0b00010000;
out timsk,r20 ;
sei

out tcnt1h,r17;
out tcnt1l,r17;

.equ kdel=200 ;(ввести 57600 для полчаса)
inc r23;
ldi r19,high(kdel);
out ocr1ah,r19;
ldi r19,low(kdel);
out ocr1al,r19;
cyc: rjmp cyc ;

zdjk:
cli
cpi r22,1
breq s1
cpi r22,2
breq s2
cpi r22,3
breq s3
cpi r22,4
breq s4
cpi r22,5
breq s5
cpi r22,6
breq s6

s1:
cpi r23,2
breq end
rjmp schet
s2:
cpi r23,4
breq end
rjmp schet
s3:
cpi r23,6
breq end
rjmp schet

s4:
cpi r23,8
breq end
rjmp schet

s5:
cpi r23,10
breq end
rjmp schet

s6:
cpi r23,12
breq end
rjmp schet

; подпрограмма антидребезга
;********************************************************************************************************

wait: push loop
ldi loop,5 ;200
wt1: dec loop
brne wt1
pop loop
ret
;*********************************************************************************************************

; подпрограмма ожидание отжатия кнопки
;*********************************************************************************************************

j1: in rin,pinb;
sbrs r18,1
rjmp j1
ret
;**********************************************************************************************************


; подпрограмма отсчета 7 сек
;******************************************************************************************************

z7: ;
ldi r20,0b10000000;
out timsk,r20 ;
ldi r21,ddel ;
out ocr2,r21 ;
out tcnt2,r17;
sei
cz0: in rin,pinb;
sbrc rin,1;
rjmp cz0;
cli
ldi r20,0b00000000;
out timsk,r20 ;
ret
;************************************************************************************************
end:
cbi portb,0;

ldi r19,0b10000000 ;
out portd,r19 ;
rjmp end

nop

; end1: sbi portb,0 ;
; nop
; nop
; rjmp end1

Re: Прошу помощи в поиске ошибки кода Atmega8

Чт июн 28, 2018 19:42:33

Вход в прерывание zdjk есть, а вот выхода из него командой reti нет. Вот и получается зависание.

Re: Прошу помощи в поиске ошибки кода Atmega8

Пт июн 29, 2018 06:34:50

По меткам schet и end беда бедная. По end залазим в бесконечный цикл, а по schet, походу, выполняем основную программу. Ошибка в организации подпрограммы обработки прерывания.

Добавлено after 2 minutes 29 seconds:
...В Atmel Studio все нормально, пошагово проходит всю программу как положено, со всеми реакциями....

Обратите внимание на то, чтобы подпрограмма обработки прерывания отрабатывалась корректно. Да, и уберите эти cli sei. Запрет и разрешение прерываний отрабатываются железом.

Re: Прошу помощи в поиске ошибки кода Atmega8

Пт июн 29, 2018 08:35:04

Если уж хочешь что бы помогли, так и оформи соответственно. А не так что бы в твоем говне люди ковырялись. Ага?
Нажимаешь Редактор и Code. Поняв?

Re: Прошу помощи в поиске ошибки кода Atmega8

Чт июл 26, 2018 21:07:06

Все NOP-ы в таблице прерываний надо обязательно на RETI заменить. Не гоже, если некоторые прерывания срабатывают по какой-либо причине, а вызывается обработка каких-нибудь других прерываний..

Re: Прошу помощи в поиске ошибки кода Atmega8

Пт июл 27, 2018 05:01:39

Вообще-то, случайных прерываний не бывает. Бывают ошибки, когда сам откроешь какое-то прерывание, а программу его обслуживания подключишь не туда, или забудешь ее подключить. И RETI в этом случае не поможет. Помогает RJMP PC. Зависло - поглядел в отладчике и увидел, на каком RJMP PC она висит.

Я уже не раз рассказывал, как это делают "по взрослому" - на тех же ARM, допустим. Таблица векторов заполняется вся, полностью, и где-то, в удобном месте программы делается таблица заглушек для всех прерываний. У "взрослых" она заполняется т.н. слабыми ссылками, которые работают только если нет нормальной ссылки. Есть нормальная программа - подключается она, нет - подключается заглушка, и при этом никто не ругается на повторение внешнего имени.

В нашей AVR-овской песочнице такого механизма нет, поэтому таблицу правим руками - понадобилось какое-то прерывание, закомментируем нужную строчку из этой таблицы, скопипастим ее в нужное место программы и вперед!

Ну, и о том, как "слегка механизировать" сочинение этой таблицы и таблицы векторов. В даташите на каждую АВР-ку есть пример заполнения таблицы векторов на АСМе. Например, у 8-й Меги он расположен на стр. 45. Вот он.
Спойлер
Код:
;addressLabels Code                             Comments
$000          rjmp   RESET                   ; Reset Handler
$001          rjmp   EXT_INT0                ; IRQ0 Handler
$002          rjmp   EXT_INT1                ; IRQ1 Handler
$003          rjmp   TIM2_COMP               ; Timer2 Compare Handler
$004          rjmp   TIM2_OVF                ; Timer2 Overflow Handler
$005          rjmp   TIM1_CAPT               ; Timer1 Capture Handler
$006          rjmp   TIM1_COMPA              ; Timer1 CompareA Handler
$007          rjmp   TIM1_COMPB              ; Timer1 CompareB Handler
$008          rjmp   TIM1_OVF                ; Timer1 Overflow Handler
$009          rjmp   TIM0_OVF                ; Timer0 Overflow Handler
$00a          rjmp   SPI_STC                 ; SPI Transfer Complete Handler
$00b          rjmp   USART_RXC               ; USART RX Complete Handler
$00c          rjmp   USART_UDRE              ; UDR Empty Handler
$00d          rjmp   USART_TXC               ; USART TX Complete Handler
$00e          rjmp   ADC                     ; ADC Conversion Complete Handler
$00f          rjmp   EE_RDY                  ; EEPROM Ready Handler
$010          rjmp   ANA_COMP                ; Analog Comparator Handler
$011          rjmp   TWSI                    ; Two-wire Serial Interface Handler
$012          rjmp   SPM_RDY                 ; Store Program Memory Ready Handler
;
$013 RESET:   ldi    r16,high(RAMEND)        ; Main program start
$014          out    SPH,r16                 ; Set Stack Pointer to top of RAM
$015          ldi    r16,low(RAMEND)
$016          out    SPL,r16
$017          sei                            ; Enable interrupts

Здесь приведен пример таблицы векторов. и начало программы - установка указателя стека и разрешение прерываний. Копипастим это целиком в нормальный редактор программ, подправляем пробелами или табуляциями колонки Address, Label, Code и Comments, чтобы они действительно стали колонками (я подправил пробелами, так, как движок форума не вполне адекватно реагирует на табуляции) и начинаем редактировать. Первым делом полностью убираем колонку Address, так, чтобы метка RESET (Main program start) оказалась в первой позиции. Особенно удобно, если ваш редактор поддерживает работу с вертикальным блоками, в таком редакторе это удаление делается в пару движений.

Все, таблица векторов готова. Единственное, что не подходит, это строчка

rjmp ADC ; ADC Conversion Complete Handler

Метка ADC, которую написали атмеловцы, не годится - совпадает с кодом машинной команды. Я ее исправляю на iADC. Заодно готово и начало программы.

Теперь копипастим (исправленную) таблицу векторов еще раз, уже без кусочка Main program start. Удаляем коды операции (rjmp) вместе с пробелами/табуляциями как перед, так и после них, чтобы метки, куда отсылают эти rjmp, оказались с первой позиции. После каждой из меток ставим двоеточие и, может быть, команду rjmp pc.

Все, таблица заглушек тоже готова.

Я, обычно, ставлю одну rjmp pc после всей таблицы меток. Если вдруг программа зависнет на этой команде, тогда я ставлю rjmp pc после каждой метки заглушек и разбираюсь. За все время работы с АВР-ками это пришлось сделать один раз. Вот итоговое начало программы для 8-й Меги.
Спойлер
Код:
         rjmp   RESET                   ; Reset Handler
         rjmp   EXT_INT0                ; IRQ0 Handler
         rjmp   EXT_INT1                ; IRQ1 Handler
         rjmp   TIM2_COMP               ; Timer2 Compare Handler
         rjmp   TIM2_OVF                ; Timer2 Overflow Handler
         rjmp   TIM1_CAPT               ; Timer1 Capture Handler
         rjmp   TIM1_COMPA              ; Timer1 CompareA Handler
         rjmp   TIM1_COMPB              ; Timer1 CompareB Handler
         rjmp   TIM1_OVF                ; Timer1 Overflow Handler
         rjmp   TIM0_OVF                ; Timer0 Overflow Handler
         rjmp   SPI_STC                 ; SPI Transfer Complete Handler
         rjmp   USART_RXC               ; USART RX Complete Handler
         rjmp   USART_UDRE              ; UDR Empty Handler
         rjmp   USART_TXC               ; USART TX Complete Handler
         rjmp   iADC                    ; ADC Conversion Complete Handler
         rjmp   EE_RDY                  ; EEPROM Ready Handler
         rjmp   ANA_COMP                ; Analog Comparator Handler
         rjmp   TWSI                    ; Two-wire Serial Interface Handler
         rjmp   SPM_RDY                 ; Store Program Memory Ready Handler
;
RESET:   ldi    r16,high(RAMEND)        ; Main program start
         out    SPH,r16                 ; Set Stack Pointer to top of RAM
         ldi    r16,low(RAMEND)
         out    SPL,r16

; Здесь пишем свою программу - то, что должно выполняться при закрытых прерываниях.

         sei                            ; Enable interrupts

А здесь - продолжение при открытых прерываниях



; Заглушки для неиспользуемых прерываний:

EXT_INT0:                ; IRQ0 Handler
EXT_INT1:                ; IRQ1 Handler
TIM2_COMP:               ; Timer2 Compare Handler
TIM2_OVF:                ; Timer2 Overflow Handler
TIM1_CAPT:               ; Timer1 Capture Handler
TIM1_COMPA:              ; Timer1 CompareA Handler
TIM1_COMPB:              ; Timer1 CompareB Handler
TIM1_OVF:                ; Timer1 Overflow Handler
TIM0_OVF:                ; Timer0 Overflow Handler
SPI_STC:                 ; SPI Transfer Complete Handler
USART_RXC:               ; USART RX Complete Handler
USART_UDRE:              ; UDR Empty Handler
USART_TXC:               ; USART TX Complete Handler
iADC:                    ; ADC Conversion Complete Handler
EE_RDY:                  ; EEPROM Ready Handler
ANA_COMP:                ; Analog Comparator Handler
TWSI:                    ; Two-wire Serial Interface Handler
SPM_RDY:                 ; Store Program Memory Ready Handler
            rjmp    pc


Достоинства этого подхода:
- нет брошенных прерываний;
- надежно распознается ошибка "не обслужено / обслужено не то прерывание";
- не надо сочинять метки для программ обслуживания прерываний - их заботливо предоставилипрограммисты Atmel (не считая косяка с iADC);
- не надо напрягаться с набирательством официально рекомендованных длинных пар типа
Код:
    org     INT0addr
    rjmp    <метка в моей программе, которую тоже надо сочинить>
и, при этом, не забыть какое-то из прерываний, иначе останется "дырка"

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

Re: Прошу помощи в поиске ошибки кода Atmega8

Пт июл 27, 2018 19:50:41

B@R5uk писал(а):...Не гоже, если некоторые прерывания срабатывают по какой-либо причине, а вызывается обработка каких-нибудь других прерываний..
Непонятно откуда, но периодически такое вылазит в форумах. Звучит так же, а что если jmp addss сработает как jmp rand_addss. Второй утверждение же врядли кто посчитает не абсурдным, но это одно и тоже.
afz писал(а): У "взрослых" она заполняется т.н. слабыми ссылками
В асме такое бывает?
afz писал(а):Помогает RJMP PC.
Лучше сделать обработчик по умолчанию, и то он нужен для обработки исключений, коих нет avr (вроде).

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 03:39:54

Непонятно откуда, но периодически такое вылазит в форумах.
Угу, еще и, почему-то, для этих неожиданных прерываний предлагают молча выходить из них. Хотя незапланированное прерывание может быть только из-за ошибки в программе. И вот для поиска таких ошибок нужна именно заглушка типа RJMP PC. Зависла программа, смотришь в отладчике и видишь, что вылезло не то прерывание, которое ожидалось.

А организовать это дело - запросто. Загнал 8-й Меге в регистр TIMSK не тот бит, который хотел, и радуйся жизни. И если для всех "случайных" прерываний поставить RETI, эту ошибку придется искать очень долго.

В асме такое бывает?
Во "взрослых" асмах - естественно, да. В нашей "песочнице", естественно, нет.

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 10:19:00

afz писал(а):Во "взрослых" асмах - естественно, да.
Можно пример?

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 16:11:45

Легко. Впрочем, здесь это оффтопик, поэтому уберу-ка я все это дело под спойлер.
СпойлерБерем любой кейловский проект STM32 и ищем в его папке (обычно, в подоглавлении RTE\Device\<чуть укороченное название контроллера>) файл startup_stm32*.s. У меня, для контроллера STM32F103C8T6, это RTE\Device\STM32F103C8\startup_stm32f10x_md.s, каковой я и выкладываю.

Здесь от метки __Vectors до метки __Vectors_End находится таблица векторов. В отличие от AVR, у STM32 (да и у всех АРМов) в таблице векторов лежат не команды переходов, а только адреса, то есть процессор не просто переходит по адресу вектора, а достает из этого вектора адрес и переходит по нему. Ну, и самое первое слово - это не адрес команды в программе, а адрес вершины стека.

Далее идет Reset handler, т.е. программа действий по Reset'у или включению питания. Она вызывает программу SystemInit, а затем уходит в программу __main.

Далее начинаются заглушки для неиспользуемых прерываний. Первые 9 заглушек - с NMI_Handler по SysTickHandler - индивидуальные, каждая представлена отдельной командой перехода на себя саму.

Далее целая куча меток - с WWDG_IRQHandler по USBWakeUp_IRQHandler - поставлена на одну единственную зацикленную команду, все незапланированные прерывания уйдут на нее. Да, двоеточие после метки в АРМовских асмах, обычно, не ставится. Директива ассемблера EXPORT <метка> означает, что эта метка должна считаться внешней, на нее можно ссылаться из других программ (в т.ч. отдельно оттранслированных), если где-то к ней обратятся, линкер подставит ее адрес. [WEAK] означает, что внешнее имя "слабое", если где-то встретится точно такое же внешнее имя, но не слабое, линкер подставит его вместо слабого.

Все это предоставлено разработчиками, нам, допустим, для работы с USART1, достаточно будет написать программу обслуживания этого прерывания USART1_IRQHandler() и нормальное (не слабое) внешнее имя этой программы "передавит" слабое внешнее имя заглушки, соответственно, в таблице векторов в строчке
Код:
                DCD     USART1_IRQHandler          ; USART1
вместо адреса заглушки окажется адрес этой программы.

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 16:33:56

В GCC те же вектора со слабыми ссылками на сях сделаны. С кейлом чуток только баловался. Ок, понятно, не будем тут продолжать.

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 17:07:59

Z_h_e писал(а):В GCC те же вектора со слабыми ссылками на сях сделаны.
На ассемблере аналогично.
Код:
    def_irq_handler    NMI_Handler
    def_irq_handler    HardFault_Handler
    def_irq_handler    MemManage_Handler
    def_irq_handler    BusFault_Handler
    def_irq_handler    UsageFault_Handler
    def_irq_handler    SVC_Handler
    def_irq_handler    DebugMon_Handler
    def_irq_handler    PendSV_Handler
    def_irq_handler    SysTick_Handler
    def_irq_handler    Default_Handler
Макрос def_irq_handler.
Код:
/*    Macro to define default handlers. Default handler
 *    will be weak symbol and just dead loops. They can be
 *    overwritten by other handlers */
    .macro    def_irq_handler    handler_name
    .align 1
    .thumb_func
    .weak    \handler_name
    .type    \handler_name, %function
\handler_name :
    b.
    .size    \handler_name, . - \handler_name
    .endm

Re: Прошу помощи в поиске ошибки кода Atmega8

Сб июл 28, 2018 17:36:27

Вообще-то, слабые внешние ссылки - стандартная фича всех "больших" систем. Появилось это дело, если не врет мой склероз, еще на Системе-360. Ну, и ассемблеры, обычно, поддерживают все фичи системы.

Я всего один раз встретил нечто, имеющееся в системе и не поддержанное ассемблером. Было это на Минск-32, там в загрузочных модулях, среди прочего, была команда "переслать с повторением", т.е. заданный код рассылался в группу смежных ячеек памяти, а в асме соответствующей директивы не было. И то, до конца я не уверен - я тогда наизусть знал руководство по первой версии ассемблера, а были и новее, может там это сделали, а новых руководств нам на ВЦ, почему-то, не досталось.
Ответить