Hallo alle zusammen,
Problem kurz umrissen:
Unten gezeigter Code generiert ein PWM auf PortA, sobald stress am UART
ist (viele Daten schnell hintereinander) - spinnt das PWM (wird länger,
kürzer)
Zur Schaltung:
Seriell daten komemn vom Rechner BAUD 9600, über Max232 Schaltung - da
diese mit einem anderen UC Prima zusammen arbeitet, schließe ich sie als
Fehlerquelle aus.
Der Atmega ist standartmäßig beschaltet mit nem externen Quarz 16 Mhz,
Pullup am Reset.
Atmegas hab ich auch schon 3 Kollegen durch - also wirds an ihm selber
wohl auch nicht liegen.
Für die dies genauer Intressiert:
Das ganze soll ne PWM schaltung für Servos werden. Mithilfe des Atmegas.
Da der gute Atmega teuer ist soll er 4 oder mehr Servos ansteuueren,
wodurch die "interne" PWM lösung wegfällt.
Ich habe mir also eine eigene Variante gebaut die mit Hilfe der Timer im
CTC Modus die PWM Modulation übernimmt. Das ganze funktioniert im auch
sehr schön. Die beim reset gesetzten Daten werden als PWM moduliert und
an den PINS auf PORT A ausgegeben. Nun sollte per UART die Position
gesetzt werden. Funktionuierte auch sehr gut solange langsam einzellne
Werte gesetzt werden - sobald aber richtig stress am UART war haben die
Servos angefangen rumzuspinen - das Oszi zeigte die PWM Signale sind
hinüber.
Also dachte ich: okay irgendwo in der Laufzeit der ISRs verrechnet und
habe das Problem immer weiter runtergebrochen und bin bei untem
gezeigtem Code gelandet: Der Gag - sobald Stress am UART ist spinnt das
PWM signal auf PORTA.
Irgend jemand ne Idee woran das liegen kann. Nutzen Uart und der Timer
irgendwas gemeinsam wovon ich nichts weiß...
.include "m32def.inc"
.def tmpwork=r16
.org 0
rjmp rst_handler
.org T0OVFaddr
rjmp t2_handler
t2_handler:
CLI
PUSH tmpwork
IN tmpwork, PORTA ; complement Pins on PortA
COM tmpwork
OUT PORTA, tmpwork
COM tmpwork
POP tmpwork
RETI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; "Main"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rst_handler:
CLI
;;;;;;;;;;;;;;;;;;;;;;;;
;; Init Ports
;;;;;;;;;;;;;;;;;;;;;;;;
LDI tmpwork,0xFF ; Port A as output
OUT DDRA, tmpwork
OUT PORTA, tmpwork
OUT DDRB, tmpwork
OUT PORTB, tmpwork
OUT DDRC, tmpwork
OUT PORTC, tmpwork
LDI tmpwork, 0x00
OUT PORTA, tmpwork
;;;;;;;;;;;;;;;;;;;;;;;;
;; Init Stack
;;;;;;;;;;;;;;;;;;;;;;;;
LDI tmpwork,HIGH(MAXRAM) ; Setting up Stack
OUT SPH,tmpwork
LDI tmpwork,LOW(MAXRAM) ; Setting up Stack
OUT SPL,tmpwork
;;;;;;;;;;;;;;;;;;;;;;;;;
;; Init Timer
;;;;;;;;;;;;;;;;;;;;;;;;
LDI tmpwork, (1<<CS00)
OUT TCCR0, tmpwork
LDI tmpwork, (1<<TOIE0) ; TOIE0: Interrupt bei Timer Overflow
OUT TIMSK, tmpwork
SEI
hang:
SEI
RJMP hang
Hi
Hilft dir zwar nicht bei deinem Problem:
>t2_handler:> CLI --> Unnötig> PUSH tmpwork> IN tmpwork, PORTA ; complement Pins on PortA> COM tmpwork> OUT PORTA, tmpwork> COM tmpwork --> Sinnlos> POP tmpwork> RETI
MfG Spess
Ich weiß das der Code kein UART benutzt - ich habe es ja alles
rausgehauen. Deswegen war meine Vermutung das da irgendwelche Register
oder weiß der Geier was zusammen genutzt werden.
das ich CLI und den zweiten CMP nich brauche is klar - nur wenn so
seltsame Fehler auftreten dann versucht man alles...
Achso nochwas wenn ich den RXC Pin auf out stelle hat sich das Problem -
nur bringt mich das ja nicht weiter weil ich den UART ja eigentlich
benutzen will.
Hi
>Deswegen war meine Vermutung das da irgendwelche Register>oder weiß der Geier was zusammen genutzt werden.
Mit diesem 'temp...'-Gedödel kann das eh niemand sagen. Ausserdem, wobei
das auch nicht die Ursache sein kann, solltest du dir angewöhnen in der
Interruptroutine SREG zu sichern.
>Achso nochwas wenn ich den RXC Pin auf out stelle hat sich das Problem ->nur bringt mich das ja nicht weiter weil ich den UART ja eigentlich>benutzen will.
Das das obige Programm durch einen RXD als Eingang gestört wird, halte
ich für unwahrscheinlich.
MfG Spess
@ Friedrich
Es grundsätzlich eine gute Idee genau den Code zu posten, der das
Problem zeigt. Es sei denn Du willst uns sagen, das unabhängig davon, ob
der UART-Code enthalten ist oder nicht, die PWM sich verändert sobald
Zeichen an RX ankommen, was ich aber nicht vermute.
Jedenfalls kannst Du Dir so die leicht säuerliche Reaktion erklären.
Doch genau das will ich sagen - der Code oben ist genau der (nichts dazu
oder so) den ich auf dem chip habe. Und wenn ich am UART terror mache
dann schwankt das PWM Signal.
Deswegen ist die Frage nach dem Schaltplan wohl sehr berechtigt.
Solangsam glaube ich auch das ich mich da irgendwo verbaut habe.
Bevor ich anfange die Schaltung auseinander zu nehmen wollte ich halt
vorallem sicher gehen das ich keinen Blödfehler in der Programmierung
habe.
Ich werde mich gleich mal ran machen ne Schaltplan zu machen und euch zu
zeigen.
SREG sichern werd ich machen - danke
Hi
>Doch genau das will ich sagen - der Code oben ist genau der (nichts dazu>oder so) den ich auf dem chip habe. Und wenn ich am UART terror mache>dann schwankt das PWM Signal.
Sicher? Ich habe auch schon mal einen halben Tag vergeudet, nur weil das
falsche File im Programmer stand.
MfG Spess
Allgemeiner Tip zum Ansteuern mehrerer Servos:
http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html
Schmeiß das Tasten- und ADC-Geraffel raus und verwalte die Positionen in
einem Array. Dies kannst Du dann per UART-Polling in der Mainloop mit
neuen Daten befüllen.
...
Danke für den Link ich werd ihn mir am WE mal zu gemüte führen.
Habe mittlerweile rausgefunden das der terror am UART den Effekt (PWM
Signal spinnt) nur verstärkt. Er aber auch auftritt wenn man am UART
nichts macht, nur dann eben deutlich seltener.
Zeichnung muss wohl bis nach dem WE warten, da ich jetzt wahrscheinlich
mehr Fehler zeichnen würde als drin sind.
Danke euch schonmal - ich werd auf jeden Fall berichten wenn ich neue
weiß.
Der Code-Ausschnitt oben ist fürn Popo...
Poste einen mit sämtlichen Fehlern und lass die Kritik über dich
ergehen.
So wird das nur wieder ein Kristallkugelbefragen...
spess53 schrieb:
> Hi>> Hilft dir zwar nicht bei deinem Problem:>>>t2_handler:>> CLI --> Unnötig>> PUSH tmpwork>> IN tmpwork, PORTA ; complement Pins on PortA>> COM tmpwork>> OUT PORTA, tmpwork>> COM tmpwork --> Sinnlos>> POP tmpwork>> RETI
COM setzt das Carry, was das Hauptprogramm (welches wir immer noch nicht
gesehen haben) vermutlich nicht erwartet.
Der Code ausschnitt ist kein Ausschnitt sondern der ganze Code (...
wieso glaubt mir das keiner...). Mit genau diesem Code auf dem Atmega
und Habe ich PWM Signale die nicht konstant sind. Diese veränderung am
PWM passiert selten einfach so und mit 100 % Sicherheit wenn ich an den
UART Port Signale sende
Aber vielleicht bin ich ja komplett auf der falschen fährte - deswegen
hier der ursprüngliche Code (also der der die ganzen PWM Signale für die
Servos richtig generiert etc)
@Stromversorgung: Die ist ordentlich Stabil und entpuffert. Ist eine die
ich mir auf Lochraster gelötet habe und mit der ich schon einige Ucs am
laufen hatte. Laut Oszi bricht die Spannung auch nicht ein oder
ähnliches.
Ich bin natürlich nicht gegen Fehler gefeit, aber die Versorgung wäre
eine der letzten Fehlerquellen die ich mir anschauen würde weil eben
andere UCs mit ihr ihren Dienst tun
So hier nun wie versprochen der Ursprüngliche Code:
Auch hier der Fehler die PWM generation funktioniert, und fänngt an zu
zicken (Bleibt teilweise für mehrere Sekunden auf high oder toggled im
usek takt) Wenn ich am UART schnell nacheinandern Daten anlege.
Ich hatte zuerst vermutet das die UART ISR dann zuoft aufgerufen wird
und die Timer ISR nicht zum zuge kommt aber zwischen zwei Zeichen
müssten bei Baud 9600 mehr als 1000 Takte Zeit sein (es sei denn ich hab
mich Gnadenlos verrechnet)
Schaltung folgt später - danke für eure Hilfe!
.include "m32def.inc"
.def tmpwork=r16
.def tmpwork2=r17
.def serialcount=r18
.def count=r23
.def mode=r24
.equ SCALE_64=(1<<CS22)
.equ SCALE_1=(1<<CS20)
.equ HIGH_TIME=0
.equ HIGH_TIME_SCALER=SCALE_64
.equ INDV_TIME=1
.equ INDV_TIME_SCALER=SCALE_1
.equ LOW_TIME=2
.equ LOW_TIME_COUNT=35
.equ LOW_TIME_SCALER=SCALE_64
.equ BAUD=103 ; 16MHz
;.equ BAUD=95 ; 14.7456MHz
.equ NUM_PWM=4
.equ BYTES=1
.equ RESERVED=NUM_PWM*BYTES
.equ LISTSTART=MAXRAM-RESERVED
.equ CID=0b00000 ; ChipID
.equ S_BITS=2
.equ S_CID=(CID << S_BITS) ; shifted chipid for comparison
.equ SID_MASK=((1<<S_BITS)-1) ; ServoID mask
.equ CID_MASK=~(SID_MASK) ; chipID mask
.cseg
.org 0
rjmp rst_handler
.org T2CMPaddr
rjmp t2_handler
.org URXCaddr
rjmp rxc_handler
high_handler: ; Handles T2CMP if mode=LOW_TIME
LDI mode, INDV_TIME ; switch to next mode
LDI count, 255 ; reset count for next mode (+1 will be added
@pre_end)
IN tmpwork, TCCR2
ANDI tmpwork,~((1<<CS20)|(1<<CS21)|(1<<CS22))
ORI tmpwork, INDV_TIME_SCALER
OUT TCCR2, tmpwork
RJMP pre_end
low_handler: ; Handles T2CMP if mode=HIGH_TIME
CPI count, LOW_TIME_COUNT ; waited long enough?
BRNE pre_end
LDI mode, HIGH_TIME ; switch to next mode
LDI count, 255 ; reset count for next mode (+1 will be added
@pre_end)
IN tmpwork, TCCR2
ANDI tmpwork,~((1<<CS20)|(1<<CS21)|(1<<CS22))
ORI tmpwork, HIGH_TIME_SCALER
OUT TCCR2, tmpwork
LDI tmpwork, 0xFF ; Set entire port to high
OUT PORTA, tmpwork
RJMP pre_end
t2_handler: ; Distributes T2CMP-IRQ if necessary and handles
mode=INDV_TIME
CLI ; this ISR is not nested!
PUSH tmpwork2 ; save registers, we might be coming from rxc_handler
PUSH tmpwork
PUSH ZL
PUSH ZH
CPI mode, LOW_TIME ; in LOW_TIME?
BREQ low_handler ; distribute!
CPI mode, HIGH_TIME ; in HIGH_TIME?
BREQ high_handler ; distribute!
; if this is reached, we're in INDV_TIME
LDI ZH,HIGH(LISTSTART)
LDI ZL,LOW(LISTSTART)
LDI tmpwork, 1 ; 1 will be shifted around for masking
RJMP loop_entry ; don't rotate in the first round
loop:
CLC ; We don't want a 1 to be shifted into tha mask
ROL tmpwork
loop_entry:
LD tmpwork2, Z ; Load pwm-config
CP tmpwork2,count ; switching time?!
BRNE loop_bottom
switch:
IN tmpwork2, PORTA ; Get current configuration
COM tmpwork ; Convert to mask
AND tmpwork2, tmpwork ; Set pwm pin to low
OUT PORTA, tmpwork2 ; Make it tha new configuration
COM tmpwork ; Convert back
loop_bottom:
;ADIW ZL,1
INC ZL
CPI tmpwork,1<<(NUM_PWM-1)
BRNE loop
count_check:
INC count
CPI count, 0 ; Are we done? (Overflow = 256th cycle)
BRNE end
LDI mode, LOW_TIME ; switch to next mode
IN tmpwork, TCCR2 ; set prescaler for LOW_TIME
ANDI tmpwork, ~((1<<CS22)|(1<<CS21)|(1<<CS20))
ORI tmpwork, LOW_TIME_SCALER
OUT TCCR2, tmpwork
LDI tmpwork, 0x00 ; Set entire port to low
OUT PORTA,tmpwork
RJMP end
pre_end:
INC count
end:
POP ZH
POP ZL
POP tmpwork
POP tmpwork2
RETI
rxc_handler:
CLI
PUSH tmpwork
CBI UCSRA, RXC ; ISR is here, don't nest for me!
IN tmpwork, UCSRB ; And don't nest for USARTs
ANDI tmpwork, ~(1<<RXCIE)
OUT UCSRB, tmpwork
SEI
CPI serialcount, 0 ; next is a ID?
BREQ read_id
CPI serialcount, 1 ; next is a position
BREQ write_pos
; If this is reached, we received a useless position
IN serialcount, UDR
CLR serialcount ; start all over
rxc_end:
POP tmpwork
RETI
read_id:
INC serialcount ; this a ID, next is a position
IN tmpwork, UDR ; get ID
MOV tmpwork2, tmpwork ; copy it for further manipulation, avoid stack
ANDI tmpwork,CID_MASK ; extrack ChipID
CPI tmpwork,S_CID ; does it match ours?
BREQ use_read_id ; use the servo id!
;CPI tmpwork2,0xFF ; Handshake?
;BREQ handshake
LDI serialcount, 2 ; did not match - next position is useless to us
;RCALL toggle
RJMP rxc_end
handshake:
LDI serialcount, 0 ; Reset!
RJMP rxc_end
use_read_id:
ANDI tmpwork2,SID_MASK ; extract servo id
LDI ZH,HIGH(LISTSTART)
LDI ZL,LOW(LISTSTART)
ADD ZL,tmpwork2 ; point to setup #servo_id
RJMP rxc_end
write_pos:
IN tmpwork, UDR ; get position
ST Z, tmpwork ; write to memory
CLR serialcount ; start all over
RJMP rxc_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; "Main"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rst_handler:
CLI
LDI tmpwork,0xFF ; Port A as output
OUT DDRA, tmpwork
OUT PORTA, tmpwork
OUT DDRB, tmpwork
OUT PORTB, tmpwork
LDI count,0
LDI mode,HIGH_TIME
LDI tmpwork, 0x00
LDI serialcount, 0
OUT UBRRH, tmpwork
LDI tmpwork, BAUD
OUT UBRRL, tmpwork
LDI tmpwork, (1<<RXEN)|(1<<RXCIE)
OUT UCSRB, tmpwork
LDI tmpwork, (1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL)
OUT UCSRC, tmpwork
LDI tmpwork,HIGH(LISTSTART-1) ; Setting up Stack
OUT SPH,tmpwork
LDI tmpwork,LOW(LISTSTART-1) ; Setting up Stack
OUT SPL,tmpwork
LDI ZH,HIGH(LISTSTART)
LDI ZL,LOW(LISTSTART)
;;;;;;;;;;;;;;;;;;;;;;;;
;; Example conf, FIXME
;;;;;;;;;;;;;;;;;;;;;;;;
LDI tmpwork,0
STD Z+0, tmpwork
LDI tmpwork,255
STD Z+1, tmpwork
LDI tmpwork,32*2
STD Z+2, tmpwork
LDI tmpwork,32*3
STD Z+3, tmpwork
;;;;;;;;;;;;;;;;;;;;;;;;;
;; End Example conf
;;;;;;;;;;;;;;;;;;;;;;;;
LDI tmpwork, (1<<WGM21)|HIGH_TIME_SCALER ; CTC mode and 64 prescaler
OUT TCCR2, tmpwork
LDI tmpwork, 125 ; every 125 steps
OUT OCR2, tmpwork
LDI tmpwork, (1<<OCIE2)
OUT TIMSK, tmpwork
SEI
hang:
IN tmpwork, UCSRB ; We're done, nest for Usart
ORI tmpwork, (1<<RXCIE)
OUT UCSRB, tmpwork
SEI
RJMP hang
Friedrich Wessel schrieb:
> Der Code ausschnitt ist kein Ausschnitt sondern der ganze Code (...> wieso glaubt mir das keiner...).
Weil die Behauptung so unglaublich klingt.
Bisher gibt es keine Berichte über ein ähnliches Phänomen. Und einige
die hier mitlesen sind schon ein paar Jährchen hier.
Hast du schon untersucht, ob dein µC nicht zufällig resettet und das was
du als unregelmässige PWM siehst in Wirklichkeit nicht einfach nur ein
Neustart des Programms ist?
Ja es ist sehr strange - deswegen baue ich ja auf die Erfahrung der
Leute hier weil ich seit 3 Wochen an dem Ding sitze und keine Ahnung
mehr habe wo der Fehler liegen kann.
Alles was ich tun kann sind meine Beobachtungen und Schlüsse hier zu
Posten.
Wie gesagt es kann gut sein das ich komplett dem falschen Fehler
hinterherlaufe und die Sache mit dem UART gar nicht das eigentliche
Problem ist (was ich btw. selber nicht glaube)
Wenn jemand ne Idee hat - immer her damit. Bin mittlerweile an dem Punkt
wo ich mit der Rassel im Kreis springe wenn jemand meint das könnte
helfen.
Ja Reset hab ich mit Pin abfrage und Oszi getestet - tut er nicht.
Hm... also Reset hätte ich jezt vieleicht auch vermutet.
Schonmal ein Erase gemacht? Trennst du die Stromversorgung nach der
neuprogrammierung?
Ich hatte mal das Problem das nach einem Reset irgenwelche Funktionen
(UART/Watchdog...) noch aktiv waren da ich sie im (neuen) Code nicht
explizit abgeschaltet hatte.
Ansosnten prüf mal ob der RX/TX Pin vieleicht falsch angeschlossen ist
und ein Ausgang gegen einen Eingang treibt.
Friedrich Wessel schrieb:
> rxc_handler:> CLI> PUSH tmpwork> CBI UCSRA, RXC ; ISR is here, don't nest for me!> IN tmpwork, UCSRB ; And don't nest for USARTs> ANDI tmpwork, ~(1<<RXCIE)> OUT UCSRB, tmpwork> SEI
...
> rxc_end:> POP tmpwork> RETI
1. In allen Interrupt-Handlern hast Du vergessen, das SREG zu sichern
2. Du spielst wild mit SEI und CLI Befehlen herum, die teilweise für
verschachtelte Interrupts sorgen. Während der Abarbeitung eines
Interrupts sind weitere Interrupts von Haus aus automatisch gesperrt,
und es ist zunächst eine gute Idee, das einfach mal so zu lassen.
Abhilfe:
1. In jedem Handler SREG sichern und am Ende wieder herstellen.
2. Als ersten Ansatz um Licht in die Sache zu bringen würde ich dafür
sorgen, dass im Programm genau an einer Stelle (nämlich unmittelbar von
der Main-Loop) ein Befehl "SEI" steht. Sämtliche anderen Vorkommen
von "SEI" sowie alle "CLI" sind ersatzlos zu streichen.
Hi
> LDI ZH,HIGH(LISTSTART)> LDI ZL,LOW(LISTSTART)> ADD ZL,tmpwork2 ; point to setup #servo_id> RJMP rxc_end
....
Dieser Konstrukt kann durchaus tödlich sein, da du einen eventuellen
Übertrag für ZH nicht berücksichtigst.
MfG Spess
Hallo,
für mich sieht das ganze nach einem Hardwareproblem aus:
fehlende Abblockkondensatoren?
Anschluß der Quarz-Kondensatoren an die falsche Masseleitung?
vergessene Versorgungsspannung (Phantomspeisung über UART-Eingang) oder
ähnliches?
> wo ich mit der Rassel im Kreis springe wenn jemand meint das könnte> helfen.
Spring mal mit ner Rassel im Kreis drumherum! Ich glaub, das müsste
helfen! G
Hallo
so hatte das WE über kein Internet, deswegen meld ich mich erst jetzt
wieder.
Ich habe die Schaltung nochmal komplett neu aufgebaut. Die Max232
Schaltung sieht jetzt aus wie in diesem Tutorial:
[[http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART]]
nur halt noch VCC und GND an 15 und 16 gelegt.
Die Spannungsversorgung hab ich mittlerweile mit nem fetten 4700 uF
Kondi abgeblockt (hab aber auch schon normal 10 und 100 reingebaut
gehabt)
Ich hab leider nicht viel Ahnung mit digitaler Schaltplan erstellung
aber ich hab für Atmega Beschaltung mal mein bestes Versucht (Siehe
Anhang)
Ich hoffe man kann habwegs erkennen was gemeint ist.
Die Kondis des Qaurzes liegen auf dem normalen GND der schaltung.
Versorgungsspannung liegt an und ist nochmal mit nem 1uF Kondi gepuffert
Die eigentliche Spannungsversorgung ist auf Lochraster und der Plan
lässt sich grad nur schwer auseinander puzzeln, deswegen dazu jetzt grad
keine Schaltung.
Beim Code habe ich eure Vorschläge eingebaut und erstmal die Interrupts
aufgeräumt, dann SREG gesichtert, und sicherheitshalber auch die Zeile
ADD ZL, tmpwork2 ersetzt durch den richtigen 16 bit Befehl. Hatte es aus
Geschwindigkeitsgründen rausgenommen da ich bei 4 eingestellten Servos
mit jeweils einem Byte eigentlich kein Problem bekommen sollte.
Das Problem bleibt das alte:
der Servo stellt sich in die richtige Position und das Oszi zeigt an
PORTB Pin1 auch das richtige Signal an. Wenn ich dann Daten per UART
sende, sieht das nen kurzen Moment ganz gut aus, Signal am Oszi
verändetr sich wie gesendet, und der Serv dreht. Nach ein einer Weil
fängt der Servo an zu zucken und das Signal am Pin flackert, und ist
größtenteils auf High mit winzigen unterbrechungen ca 10 us
Hie nochmal der Aktualisierte Code:
1
.include "m32def.inc"
2
3
.def tmpwork=r16
4
.def tmpwork2=r17
5
.def serialcount=r18
6
.def count=r23
7
.def mode=r24
8
9
.equ SCALE_64=(1<<CS22)
10
.equ SCALE_1=(1<<CS20)
11
.equ HIGH_TIME=0
12
.equ HIGH_TIME_SCALER=SCALE_64
13
.equ INDV_TIME=1
14
.equ INDV_TIME_SCALER=SCALE_1
15
.equ LOW_TIME=2
16
.equ LOW_TIME_COUNT=35
17
.equ LOW_TIME_SCALER=SCALE_64
18
.equ BAUD=103 ; 16MHz
19
;.equ BAUD=95 ; 14.7456MHz
20
21
22
.equ NUM_PWM=4
23
.equ BYTES=1
24
.equ RESERVED=NUM_PWM*BYTES
25
.equ LISTSTART=MAXRAM-RESERVED
26
27
.equ CID=0b00000 ; ChipID
28
.equ S_BITS=2
29
.equ S_CID=(CID << S_BITS) ; shifted chipid for comparison
30
.equ SID_MASK=((1<<S_BITS)-1) ; ServoID mask
31
.equ CID_MASK=~(SID_MASK) ; chipID mask
32
.cseg
33
.org 0
34
rjmp rst_handler
35
.org T2CMPaddr
36
rjmp t2_handler
37
.org URXCaddr
38
rjmp rxc_handler
39
40
41
t2_handler: ; Distributes T2CMP-IRQ if necessary and handles mode=INDV_TIME
42
PUSH tmpwork2 ; save registers, we might be coming from rxc_handler
43
PUSH tmpwork
44
PUSH ZL
45
PUSH ZH
46
IN tmpwork, SREG
47
PUSH tmpwork
48
49
CPI mode, LOW_TIME ; in LOW_TIME?
50
BREQ low_handler ; distribute!
51
CPI mode, HIGH_TIME ; in HIGH_TIME?
52
BREQ high_handler ; distribute!
53
54
; if this is reached, we're in INDV_TIME
55
LDI ZH,HIGH(LISTSTART)
56
LDI ZL,LOW(LISTSTART)
57
LDI tmpwork, 1 ; 1 will be shifted around for masking
58
RJMP loop_entry ; don't rotate in the first round
59
60
61
high_handler: ; Handles T2CMP if mode=LOW_TIME
62
LDI mode, INDV_TIME ; switch to next mode
63
LDI count, 255 ; reset count for next mode (+1 will be added @pre_end)
64
IN tmpwork, TCCR2
65
ANDI tmpwork,~((1<<CS20)|(1<<CS21)|(1<<CS22))
66
ORI tmpwork, INDV_TIME_SCALER
67
OUT TCCR2, tmpwork
68
RJMP pre_end
69
70
low_handler: ; Handles T2CMP if mode=HIGH_TIME
71
CPI count, LOW_TIME_COUNT ; waited long enough?
72
BRNE pre_end
73
74
LDI mode, HIGH_TIME ; switch to next mode
75
LDI count, 255 ; reset count for next mode (+1 will be added @pre_end)
76
IN tmpwork, TCCR2
77
ANDI tmpwork,~((1<<CS20)|(1<<CS21)|(1<<CS22))
78
ORI tmpwork, HIGH_TIME_SCALER
79
OUT TCCR2, tmpwork
80
LDI tmpwork, 0xFF ; Set entire port to high
81
OUT PORTA, tmpwork
82
RJMP pre_end
83
84
85
86
loop:
87
CLC ; We don't want a 1 to be shifted into tha mask
88
ROL tmpwork
89
loop_entry:
90
LD tmpwork2, Z ; Load pwm-config
91
CP tmpwork2,count ; switching time?!
92
BRNE loop_bottom
93
switch:
94
IN tmpwork2, PORTA ; Get current configuration
95
COM tmpwork ; Convert to mask
96
AND tmpwork2, tmpwork ; Set pwm pin to low
97
OUT PORTA, tmpwork2 ; Make it tha new configuration
98
COM tmpwork ; use again as counter for servo
99
loop_bottom:
100
INC ZL
101
CPI tmpwork,1<<(NUM_PWM-1)
102
BRNE loop
103
104
count_check:
105
INC count
106
CPI count, 0 ; Are we done? (Overflow = 256th cycle)
107
BRNE end
108
LDI mode, LOW_TIME ; switch to next mode
109
IN tmpwork, TCCR2 ; set prescaler for LOW_TIME
110
ANDI tmpwork, ~((1<<CS22)|(1<<CS21)|(1<<CS20))
111
ORI tmpwork, LOW_TIME_SCALER
112
OUT TCCR2, tmpwork
113
LDI tmpwork, 0x00 ; Set entire port to low
114
OUT PORTA,tmpwork
115
RJMP end
116
117
pre_end:
118
INC count
119
end:
120
121
POP tmpwork
122
OUT SREG,tmpwork
123
POP ZH
124
POP ZL
125
POP tmpwork
126
POP tmpwork2
127
128
RETI
129
130
131
132
rxc_handler:
133
PUSH tmpwork
134
IN tmpwork, SREG
135
PUSH tmpwork
136
137
CPI serialcount, 0 ; next is a ID?
138
BREQ read_id
139
CPI serialcount, 1 ; next is a position
140
BREQ write_pos
141
142
; If this is reached, we received a useless position
143
IN serialcount, UDR
144
CLR serialcount ; start all over
145
146
rxc_end:
147
POP tmpwork
148
OUT SREG,tmpwork
149
POP tmpwork
150
RETI
151
152
read_id:
153
INC serialcount ; this a ID, next is a position
154
IN tmpwork, UDR ; get ID
155
MOV tmpwork2, tmpwork ; copy it for further manipulation, avoid stack
156
ANDI tmpwork,CID_MASK ; extrack ChipID
157
CPI tmpwork,S_CID ; does it match ours?
158
BREQ use_read_id ; use the servo id!
159
LDI serialcount, 2 ; did not match - next position is useless to us
160
RJMP rxc_end
161
162
handshake:
163
LDI serialcount, 0 ; Reset!
164
RJMP rxc_end
165
166
use_read_id:
167
ANDI tmpwork2,SID_MASK ; extract servo id
168
LDI ZH,HIGH(LISTSTART)
169
LDI ZL,LOW(LISTSTART)
170
ADD ZL,tmpwork2 ; point to setup #servo_id
171
RJMP rxc_end
172
173
write_pos:
174
IN tmpwork, UDR ; get position
175
ST Z, tmpwork ; write to memory
176
CLR serialcount ; start all over
177
RJMP rxc_end
178
179
180
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
181
;; "Main"
182
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
183
184
rst_handler:
185
CLI
186
187
;;;;;;;;;;;;;;;;;;;;;;;;
188
;; PORT Conf
189
;;;;;;;;;;;;;;;;;;;;;;;;
190
191
LDI tmpwork,0xFF ; Port A as output
192
OUT DDRA, tmpwork
193
OUT PORTA, tmpwork
194
OUT DDRB, tmpwork
195
OUT PORTB, tmpwork
196
197
;;;;;;;;;;;;;;;;;;;;;;;;
198
;; Setup UART
199
;;;;;;;;;;;;;;;;;;;;;;;;
200
201
LDI count,0
202
LDI mode,HIGH_TIME
203
LDI tmpwork, 0x00
204
LDI serialcount, 0
205
OUT UBRRH, tmpwork
206
LDI tmpwork, BAUD
207
OUT UBRRL, tmpwork
208
LDI tmpwork, (1<<RXEN)|(1<<RXCIE)
209
OUT UCSRB, tmpwork
210
LDI tmpwork, (1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL)
211
OUT UCSRC, tmpwork
212
213
214
;;;;;;;;;;;;;;;;;;;;;;;;
215
;; Setup Memory and Stack
216
;;;;;;;;;;;;;;;;;;;;;;;;
217
218
219
LDI tmpwork,HIGH(LISTSTART-1) ; Setting up Stack
220
OUT SPH,tmpwork
221
LDI tmpwork,LOW(LISTSTART-1) ; Setting up Stack
222
OUT SPL,tmpwork
223
224
225
LDI ZH,HIGH(LISTSTART)
226
LDI ZL,LOW(LISTSTART)
227
228
229
230
;
231
;;;;;;;;;;;;;;;;;;;;;;;;;
232
;; Setup Timer
233
;;;;;;;;;;;;;;;;;;;;;;;;
234
235
LDI tmpwork, (1<<WGM21)|HIGH_TIME_SCALER ; CTC mode and 64 prescaler