Forum: Projekte & Code 16x PWM mit ATmega8 + I2C / TWI


von Markus -. (mrmccrash)


Angehängte Dateien:

Lesenswert?

Glück Auf!

Ich habe hier eine Software PWM geschrieben, die auf einem ATmega8 mit
8Mhz internem Takt 16 Kanäle ansteuern kann. Die Ausgänge laufen auf
400Hz, was ausreichend ist für LED Ansteuerung u.ä.

Der Code ist in Assembler geschrieben und schon etwas auf
Geschwindigkeit (möglichst wenige CPU-Zyklen pro Durchlauf) optimiert.
Die Größe des Codes spielt momentan keine Rolle, Assembliert ist das
ganze grade mal 820 Byte groß...

Momentan läuft nur ein kleines Demoprogramm (Wechselblinker) darauf,
der TWI/I2C Teil ist noch in Arbeit. Als Ausgänge benutze ich die Ports
B und D, was die Nutzung eines ext. Oszillators/Quarz sowie des UART
ausschließt.

Die Pins PortC0-3 sind unbelegt, diese können z.b. für die externe
Adresszuweisung oder für die Erfassung von Analogwerten verwendet
werden.

Die TWI Schnittstelle werde ich als nächstes in Angriff nehmen.
Für Konstruktive Kritik bin ich jederzeit offen!

_.-=: MFG :=-._

von Markus -. (mrmccrash)


Lesenswert?

hm, scheinbar hab ich noch einen schweren Bug drin, mit diesem Code
passiert an den Ausgängen irgendwie gar nix.

Mal schauen, morgen werde ich das ganze nochmal gründlich
überarbeiten.

_.-=: MFG :=-._

von Markus -. (mrmccrash)


Angehängte Dateien:

Lesenswert?

So, nach längerer Problemsuche habe ich meine Logikfehler rausbekommen.

Im Anhang ist der neue, funktionierende Code.

Schuld war ein Fehler bei der SRAM Adressierung sowie bei der
Auswertung der Schwellwerte.

_.-=: MFG :=-._

von Bernhard S. (bernhard)


Lesenswert?

Hallo Marcus,

hab gerade mal Deinen ASSEMBLER-CODE überflogen.

Soll jetzt aber keine Nörgelei sein,

clr XH
ldi XL, low(0x0060)

besser wäre:

ldi XH, high(0x0060)
ldi XL,  low(0x0060)


------

ldi tmp1, 0b00000010  ; Timer 0
out TCCR0, tmp1    ; Prescaler 8

besser wäre:

ldi tmp1, 1<<....  ; Timer 0
out TCCR0, tmp1    ; Prescaler 8


-------

Bei "Interruptroutinen" würde ich sicherheitshalber noch SREG
sichern, denn man(n) weiß nich wan der Interrupt zuschlägt.

Sollte es dann Probleme mit SREG geben, dann sucht man den Fehler
stundenlang.

Bernhard

von Markus -. (mrmccrash)


Angehängte Dateien:

Lesenswert?

Glück Auf!

Hier mal ein Update des Codes.

Mittlerweile habe ich das TWI Interface implementiert, es fehlt nur
noch die Auswertung der übermittelten Kommandobytes.

Ich habe die PWM Routine komplett umgebaut, es wird jetzt alles im
Interrupt ausgeführt. Ausserdem habe ich das ganze nochmals gekürzt,
assembliert ist das Programm nur 604 Byte groß. Eingestellt ist die PWM
jetzt auf 100Hz, mit einer Auflösung von 100 Schritten, was ausreichend
ist für die Ansteuerung von Leds o.ä.

Sobald ich die Auswertung der Kommandos fertig habe und das ganze
erfolgreich getestet ist, gibts auch noch einen Beispiel-Schaltplan +
Platinenlayout.

@Bernhard:
Deine Tipps habe ich in der neuen Version berücksichtigt, danke!

_.-=: MFG :=-._

von Bernhard S. (bernhard)


Lesenswert?

Hallo Markus,

Dein Pogramm-Code sieht doch ganz vernünftig aus,

großes LOB an Dich.

Bernhard

von Markus -. (mrmccrash)


Angehängte Dateien:

Lesenswert?

Glück Auf!

nach einiger Zeit konnte ich mich mal wieder mit dem Programm
beschäftigen.
Im Anhang ist die aktuellste Version des Sourcecodes.

Leider hatte ich bisher mangels pc <-> i2c Interface noch keine
möglichkeit, das TWI Interface auf Funktionalität zu prüfen.

Das Protokoll für die Steuerung ist ganz einfach aufgebaut:

- Ansteuerung immer mit 2-Byte Befehlen
- 1. Byte bestimmt die Funktion,
- 2. Byte übergibt Parameter

Befehle:
0x01 & 0x02 sind zzt nur testweise implementiert

0x08 - Setze alle Kanäle auf Wert aus 2tem Byte
0x09 - wie 0x08, nur faden statt setzen

0x10 - 0x1F -> Setze Kanal 1 - 15 auf Wert
0x20 - 0x2F -> Fade Kanal 1 - 15 auf Wert

Beispiel:
0x08 0x00 - Setze alle Kanäle auf 0%
0x15 0x35 - Setze Kanal 6 auf 53%
0x2C 0x0A - Fade Kanal 13 auf 10%
0x09 0x32 - Fade alle Kanäle auf 50%

Ich hoffe es funktioniert auf Anhieb, wenn Fehler auftreten immer her
damit!

_.-=: MFG :=-._

von gunni (Gast)


Lesenswert?

Hallo.

Genau sowas suche ich.
Allerdings mit einer auflösung von 8 Bit. (256 schritte)
Wäre auch nicht weiter wild, wenn ich mit 16 MHz als MCU Frequenz 
arbeiten müsste.
Könntest du mir den Code dementsprechend umbauen?
Leider habe ich von Assembler gar keine ahnung.
Ich prügel mich gerade mit C rum, und das reicht mir schon.

Gruß

von TravelRec. (Gast)


Lesenswert?

>Ich prügel mich gerade mit C rum, und das reicht mir schon.

Dann lern´ doch ASM, ist eigentlich einfacher und absolut logisch, man 
muß sich halt um alles selber kümmern, aber dafür weiß man meist auch 
genau, was der Controller treibt (oder soll).

von Markus (Gast)


Lesenswert?

Glück Auf!

ganz einfach:
du setzt die Konstante "PWM_MAX" auf 255 (d.h. 256 Schritte auflösung)
und die Konstante "TIM0_ST" auf 216 (dass ist der teiler um dann wieder 
auf die Frequenz von 100Hz zu kommen)

Die Werte ermitteln sich so:

CPUCLK = prescaler * (255 - TIM0_ST) * (PWM_MAX + 1) * 100Hz

also hier:

8.000.000Hz = 8 * (255 - 216) * (255 + 1) * 100Hz

die 216 in TIM0_ST ist etwas aufgerundet, mit TIM0_ST = 215 gehts auch 
net ganz auf...

_.-=: MFG :=-._

PS: 16MHz geht nicht, da die XTAL Anschlüsse durch die PWM belegt 
sind...
PPS: Das I2C Interface ist immer noch Beta und (leider noch) 
undokumentiert, d.h. es kann funktionieren, muss aber nicht...

von Andreas C. (acdc)


Lesenswert?

Hallo Markus !

Gibt es eine Möglichkeit, diesen Assemblercode in ein C-Programm 
einzubinden, und so einen Ablauf ohne Steuerung von außen zu erreichen ? 
Ich möchte ungern einen zweiten Controller dafür "opfern" - wobei ich 
denke, dass es bestimmt auch beides in einem Controller geht - ich weiß 
eben nur nicht, wie !

Gruß, Andreas

von Markus -. (mrmccrash)


Lesenswert?

Glück Auf!

Hm, also mit dem einbetten in C-code bin ich leider nicht so bewandert. 
Aber irgendwo in den tiefen der Codesammlung versteckt findet sich afaik 
auch ein PWM-Code in C, könnte der dir weiterhelfen?

_.-=: MFG :=-._

von Andreas C. (acdc)


Lesenswert?

Hallo Markus !

Wenn der Code das kann, was Dein Code kann, dann ist die Antwort auf 
Deine Frage "Ja".
Ich stelle mir das mit dem Einbinden so vor, dass der Assemblerteil 
quasi eigenständig läuft, und ich mit dem C-Teil die Register 
manipuliere, um die gewünschte Art der Darstellung zu erreichen. Dafür 
könnte aus Deinem Code die komplette I2C-Routine gelöscht werden.
Vielleicht liest ja jemand mit, der mir erklären kann, wie man diese 
Einbettung von Assembler in C vornimmt, und was man da beachten muss ?

Gruß, Andreas

von koohbraa (Gast)


Lesenswert?

Hallo,
ich habe mir deinen Code geladen und bin gerade beim ausprobieren - auch 
was die kommunikation via twi bzw. i2c angeht. Doch leider muß ich 
feststellen, dass die i2c kommunikation nicht funktioniert - liegt es an 
mir, oder ist dort u.U. noch ein Fehler drin???

MfG

von Markus -. (mrmccrash)


Lesenswert?

Hallo!

Leider ist es möglich, dass es an dem Code liegt - seit meinem letzten 
Post habe ich nicht weiter daran gearbeitet, mangels Zeit und Bedarf 
daran.

Ich befürchte, dass der I2C Part noch einiges an Überarbeitung und 
Optimierung braucht. Der Code, so wie er jetzt ist, ist in großen Teilen 
nach den Zustandsbeschreibungen im ATmega8 Datenblatt sowie der Atmel 
Application Note für TWI entstanden.

Sorry dass ich dir nicht weiter helfen kann dabei :-(

_.-=: MFG :=-._

von cmb (Gast)


Lesenswert?

Hallo Markus,

ich habe folgende Zeile korrigiert - damit läuft es dann auch

ALT:
1
TWICLR:        ; TWINT loeschen, wieder empfangsbereit gehen
2
  ;ldi tmp1, (1<<TWINT)|(1<<TWEA)
3
  ;out TWCR, tmp1

NEU:
1
  ldi temp, 1<<TWINT|1<<TWEA|1<<TWEN|1<<TWIE

Gruß Jonas

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
Noch kein Account? Hier anmelden.