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
>Der Gag - sobald Stress am UART ist spinnt das >PWM signal auf PORTA. Kann nicht sein. Dein Code benutzt keinen UART.
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
> Nutzen Uart und der Timer irgendwas gemeinsam wovon ich nichts weiß...
Die Versorgungsspannung und den uC.
Zeig doch mal den Schaltplan...
@ 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.
Hallo, ich wollte hier niemanden verärgern oder vor den Kopf stoßen. Schuldigung wenn ich es doch getan habe.
1 | Es sei denn Du willst uns sagen, das unabhängig davon, ob |
2 | der UART-Code enthalten ist oder nicht, die PWM sich verändert sobald |
3 | Zeichen an RX ankommen, was ich aber nicht vermute. |
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...
Ich würde vermuten das die Stromversorgung nicht das gelbe vom Ei ist... Abblockkondesatoren dran?
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.
1 | Der Code-Ausschnitt oben ist fürn Popo... |
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.
hang: IN tmpwork, UCSRB ; We're done, nest for Usart ORI tmpwork, (1<<RXCIE) OUT UCSRB, tmpwork SEI <<<was soll das da? RJMP hang
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 |
236 | OUT TCCR2, tmpwork |
237 | LDI tmpwork, 125 ; every 125 steps |
238 | OUT OCR2, tmpwork |
239 | LDI tmpwork, (1<<OCIE2) |
240 | OUT TIMSK, tmpwork |
241 | |
242 | ;;;;;;;;;;;;;;;;;;;;;;;; |
243 | ;; Example conf |
244 | ;;;;;;;;;;;;;;;;;;;;;;;; |
245 | |
246 | LDI tmpwork,255 |
247 | STD Z+0, tmpwork |
248 | LDI tmpwork,255 |
249 | STD Z+1, tmpwork |
250 | LDI tmpwork,32*2 |
251 | STD Z+2, tmpwork |
252 | LDI tmpwork,32*3 |
253 | STD Z+3, tmpwork |
254 | |
255 | |
256 | |
257 | hang: |
258 | SEI |
259 | RJMP hang |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.