MCP4822 per SPI ansteuern.

Gottfried

Neues Mitglied
03. Juli 2014
13
0
1
84437 Reichertsheim
Sprachen
  1. Assembler
Servus zusammen,

ich versuche gerade mit mehr oder weniger Erfolg einen MCP4822 dual-DAC via SPI anzusteuern. Aber so recht will es nicht klappen.
Hab nun mal ein kleines seperates Programm geschrieben um es zu testen.
Am Anfang werden die beiden Wandler DACA und DACB auf 0 gesetzt. Das funktioniert.
Nach betätigen eines Tasters werden die beiden Wandler mit dem Wert 4095 gefüttert. Klappt auch, beide geben ca. 2,03 Volt aus.
Mit jedem weiteren Tastendruck werden beide Wandlerwerte um 128 verringert. Jetz geht aber nur noch DACB mit. DACA bleibt auf 2,03 Volt stehen und ich weiß nicht warum.:(
Ich verwende einen ATmega328PU mit intern 8Mhz und CKDIV8.
Seltsam erscheint mir, dass der MCP4822 lt. Datenblatt die Daten bei steigender Flanke einliest. Das ist beim ATmega Mode 0/0 oder 1/1.
Aber da geht gar nichts. Nur bei folgender Einstellung geht überhaupt was rüber:
ldi temp1, (1<<SPE) | (1<<MSTR) | (0<<DORD) | (0<<SPR0) | (0<<CPOL) | (1<<CPHA)
out SPCR, temp1
Wenn ich das Datenblatt richtig lesen kann, taktet der ATmega dann bei fallender Flanke.
Der Wandler verträgt Signale bis 25Mhz. Da bin ich weit drunter. Hat jemand eine Ahnung wie schnell der SPI-CLK beim ATmega max. sein kann/darf? Bei normalem Amateur-Platinenlayout.

Ich Weiß aus Erfahrung, dass man die kleinen Fehler im Code oft einfach nicht mehr sieht. Evtl weiß jemand Rat.
Der Aufbau sieht folgendermaßen aus:
An der SPI-Schnittstelle hängt der Wandler. Signale sind am Oszi erkennbar.
An PortB0 ist eine Led angeschlossen. Die zeigt mir bei jedem Tastendruck an, das sich was tut (an/aus).
An PortB1 ist der Taster angeschlossen.
CS für den Wandler ist mit SS (Port B2) verbunden und mit einem 10k Widersand nach + verbunden. LDAC ist an GND.

Der Taster wird per TimerIRQ entprellt.
Ich vermute es liegt an den Steuerbits des Wandlers. Aber Anfangs geht es ja.

Den Code hab ich mit angehängt, und hoffentlich nichts wichtiges vergessen. Falls mir jemand einen hinweis geben kann bin ich sehr dankbar. Im Netz findet sich wenig zu dem Wandler und wen, dann in C. C verstehe ich aber leider nicht.

Danke und Gruss

Gottfried
 

Anhänge

  • MCP4822.asm
    10,5 KB · Aufrufe: 7
Hallo Wolfgang,

ich finde es besser, wenn der code hier in lesbarer Form (in Code-Tags) steht - dann muß man sich das nicht auf's Mobile laden, und nach 'nem geeignettem Betrachter suchen...
Sähe dann hier so aus:
Code:
 /* ext Oszillator 20MHz


; CLKDIV8

; CK = 8MHz 

; => Fuse_low = ........ = 0xxx
; => Fuse_High =........ = 0xxx




*/
.include "g:/m328Pdef.inc"


; ***** INTERRUPT VECTORS ************************************************
.org 0x0000
  rjmp Init ; RESET 
.org 0x0002	; External Interrupt Request 0
  reti 
.org 0x0004	; External Interrupt Request 1
  reti 
.org 0x0006	; Pin Change Interrupt Request 0
  reti 
.org 0x0008	; Pin Change Interrupt Request 0
  reti 
.org 0x000a	; Pin Change Interrupt Request 1
  reti 
.org 0x000c	; Watchdog Time-out Interrupt
  reti 
.org 0x000e	; Timer/Counter2 Compare Match A
  reti 
.org 0x0010	; Timer/Counter2 Compare Match A
  reti 
.org 0x0012	; Timer/Counter2 Overflow
  reti 
.org 0x0014	; Timer/Counter1 Capture Event
  reti
.org 0x0016	; Timer/Counter1 Compare Match A
  reti
.org 0x0018	; Timer/Counter1 Compare Match B
  reti
.org 0x001a	; Timer/Counter1 Overflow
  reti
.org 0x001c	; TimerCounter0 Compare Match A
  reti 
.org 0x001e	; TimerCounter0 Compare Match B
  reti 
.org 0x0020	; Timer/Couner0 Overflow
  rjmp TIM0_OVF 
.org 0x0022	; SPI Serial Transfer Complete
  reti 
.org 0x0024	; USART Rx Complete
  reti 
.org 0x0026	; USART, Data Register Empty
  reti 
.org 0x0028	; USART Tx Complete
  reti 
.org 0x002a	; ADC Conversion Complete
  reti 
.org 0x002c	; EEPROM Ready
  reti 
.org 0x002e	; Analog Comparator
  reti 
.org 0x0030	; Two-wire Serial Interface
  reti 
.org 0x0032	; Store Program Memory Read
  reti 

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.def CNT_Step     = R9   ; dient zum Entprellen des Tasters
.def CV_A_H       = R10  ; DAC Wert f�r WaveShape
.def CV_A_L       = R11  ; DAC Wert f�r WaveShape
.def CV_B_H       = R12  ; DAC Wert f�r PWCV
.def CV_B_L       = R13  ; DAC Wert f�r PWCV

.def temp1        = R25  ; Zwischenspeicher allgemein 
.def temp2        = R26  ; Zwischenspeicher allgemein 
.def temp3        = R27  ; Zwischenspeicher allgemein 

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    .equ CNT_0            = 0     ;  
    .equ CNT_1            = 1     ;
	.equ CNT_2            = 2     ;
	.equ CNT_3            = 3     ;
	.equ CNT_4            = 4     ;
	.equ Merker_Input     = 5     ;
	.equ Merker_Taste     = 6     ;
	.equ Taste_ON         = 7     ;

    .equ W_CNT_0          = 0x01    ;
    .equ W_CNT_1          = 0x02    ;
	.equ W_CNT_2          = 0x04    ;
	.equ W_CNT_3          = 0x08    ;
	.equ W_CNT_END        = 0x10    ;
	.equ W_Merker_Input   = 0x20    ;
	.equ W_Merker_Taste   = 0x40    ;
	.equ W_Taste_ON       = 0x80    ;

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 INIT:

    ldi temp1, LOW(RAMEND)
    out SPL, temp1
    ldi temp1, HIGH(RAMEND)
    out SPH, temp1

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 Timer0 normal mode

 CS02 | CS01 | CS00     Description
  0       0      0      No clock source (Timer/Counter stopped)
  0       0      1      No prescaling
  0       1      0      clk  /8 (From prescaler)
  0       1      1      clk  /64 (From prescaler)
  1       0      0      clk  /256 (From prescaler)
  1       0      1      clk  /1024 (From prescaler)
  1       1      0      External clock source on T0 pin. Clock on falling edge.
  1       1      1      External clock source on T0 pin. Clock on rising edge.

*/
	ldi temp1, 0<<CS00 | 1<<CS01 | 0<<CS02
	out TCCR0B, temp1


	; Timer0 Overflow Interrupt enable
	ldi temp1, (1<<TOIE0)
	sts TIMSK0, temp1
    

	sei

/* ************************************************************    
  
    ; SPI einrichten


    Konfigurierung DAC MCP4822
    -------------------------------------------------------------------------------------------
    bit 15 A/B: DACA or DACB Select bit | bit 14          | bit 13 GA: Output Gain Select bit |
    1 = Write to DACB                   | Don�t Care      | 1 = 1x (VOUT = VREF * D/4096)     |
    0 = Write to DACA                   |                 | 0 = 2x (VOUT = 2 * VREF * D/4096) |
    ------------------------------------------------------|-----------------------------------|
    bit 12 SHDN: Output Power-down Control bit            | bit 11-0 D11:D0: DAC Data bits    |
    1 = Output Power-down Control bit                     |                                   |
    0 = Output buffer disabled, Output is high-impedance  |                                   |
    -------------------------------------------------------------------------------------------
*/


.equ SPI_DDR      = DDRB
.equ SPI_PORT     = PORTB
.equ LED          = PB0
.equ Taster       = PB1
.equ SPI_SS       = PB2
.equ SPI_MOSI     = PB3
.equ SPI_MISO     = PB4
.equ SPI_CLK      = PB5 
.equ Select       = 7
.equ Vref         = 5
.equ SHDN         = 4

;    Konfigurierung DAC MCP4822
;    LDAC liegt an GND

    in    temp1, SPI_DDR
    ori   temp1 , 1<<SPI_SS
    out   SPI_DDR,  temp1   ; DDRB

    in    temp1, SPI_DDR
    ori   temp1 , 1<<SPI_CLK | 1<<SPI_MOSI | 1<<Led | 0<<Taster
    out   SPI_DDR,  temp1   ; DDRB

	ldi   temp1, (1<<SPE) | (1<<MSTR) | (0<<DORD) | (0<<SPR0) | (0<<CPOL) | (1<<CPHA)
    out   SPCR, temp1

	ldi   temp1, (1<<SPI2X)              ;1= double speed aktivieren
    out   SPSR, temp1

    cbi SPI_PORT, SPI_SS                 ; DAC CS auf H = keine �bertragung


; ************************************************************   

    ldi temp1, 0<<Select | 1<<Vref | 0<<SHDN   ; CV auf 0 Volt setzen um definierten Anfangszustand zu haben.
    ldi temp2, 0x00
    rcall SPI_Out  	                           ; CV ausgeben auf DAC-A
    in    temp1, SPDR                          ; SPIF l�schen 

    ldi temp1,  1<<Select | 1<<Vref | 0<<SHDN  ; CV auf 0 Volt setzen um definierten Anfangszustand zu haben.
    ldi temp2, 0x00
    rcall SPI_Out  	                           ; CV ausgeben auf DAC-B
    in    temp1, SPDR                          ; SPIF l�schen 

  Set_CV:

    .equ CV_A = 4095                           ; DAC Wert auf max.
    .equ CV_B = 4095

    ldi temp1,  HIGH (CV_A)
    mov CV_A_H, temp1
    ldi temp1,  LOW (CV_A)
    mov CV_A_L, temp1

    ldi temp1,  HIGH (CV_B)
    mov CV_B_H, temp1
    ldi temp1,  LOW (CV_B)
    mov CV_B_L, temp1



  main:

    sbi SPI_PORT, Led                   ; Led ausschalten.



    Warte1_auf_Taster:
    sbrs CNT_Step, Taste_ON             ; Taster gedr�ckt ?
    rjmp Warte1_auf_Taster              ; Nein. => Warten

    cbi SPI_PORT, Led                   ; Led einschalten.

    mov   temp1, CV_A_H
    mov   temp2, CV_A_L
    andi  temp1, 0x0f
    sbr   temp1, 0<<Select | 1<<Vref | 0<<SHDN     ;DAC Kanal A
    rcall SPI_Out	                               ; CV ausgeben
    in    temp1, SPDR                              ; SPIF l�schen 

    mov   temp1, CV_B_H
    mov   temp2, CV_B_L
    andi  temp1, 0x0f
    sbr   temp1, 1<<Select | 1<<Vref | 0<<SHDN     ;DAC Kanal B
    rcall SPI_Out                                  ; CV ausgeben
    in    temp1, SPDR 

; CV-WERT A um 128 verringern.

	mov   temp1, CV_A_L
	mov   temp2, CV_A_H
	cpi   temp2, 0x00
    breq  Set_CV                       ; Wert = 0. Maximalwerte holen
    subi  temp1, 0x80                  ; subtrahieren
    sbci  temp2, 0x00
	mov   CV_A_L, temp1                ; zur�ckspeichern
	mov   CV_A_H, temp2

; CV-WERT B um 128 verringern.
	mov   temp1, CV_B_L
	mov   temp2, CV_B_H
    subi  temp1, 0x80                  ; subtrahieren
    sbci  temp2, 0x00
	mov   CV_B_L, temp1                ; zur�ckspeichern
	mov   CV_B_H, temp2

    Warte2_auf_Taster:
    sbrc CNT_Step, Taste_ON            ; Taster gedr�ckt ?
    rjmp Warte2_auf_Taster             ; Ja. => Warten

    rjmp main

; ************************************************************

    SPI_Out:

       cbi   SPI_PORT, SPI_SS          ; CS auf L startet �bertragung zum DAC
       out   SPDR, temp1

       Wait_WS_1:                      ;  Wait for tx complete	
	   in    temp1, SPSR
       sbrs  temp1, SPIF      
       jmp   Wait_WS_1

       out   SPDR, temp2 

	Wait_WS_2:                         ;  Wait for tx complete	
	   in    temp1, SPSR
       sbrs  temp1, SPIF      
       jmp   Wait_WS_2
       

    ;  �bertragung fertig

	   sbi   SPI_PORT, SPI_SS          ; CS auf H beendet �bertragung zum DAC

     ret

; ************************************************************

    TIM0_OVF:

    push temp1                        ; Register 1 reten
	push temp2                        ; Register 2 reten
	push temp3                        ; Register 3 reten

    in temp1, SREG                    ; Status-Register reten
    push temp1

 ; --------------------------------
  ; Steptaster entprellen
  ; --------------------------------
    Test_Step:

    mov temp1, CNT_Step              ; Z�hler f�r die Entprellung holen
	sbrc temp1, Taste_ON             ; Taste bereits ON ?
    rjmp Step_10_entprellen          ; ja. Entprellen 1 nach 0. Taste wird losgelassen

    Step_01_entprellen:              ; Entprellen 0 nach 1. Taste wird gedr�ckt
  ; --------------------------------
	sbic  PINB, Taster               ; Taste gedr�ckt
    rjmp  CLR_CNT_STEP               ; Nein. Clear Counter Step. Keine Entprellung
    
    inc temp1                        ; Ja. CNT erh�hen. H-Pegel z�hlen
	sbrs temp1, CNT_3                ; Z�hlerende erreicht ?
    rjmp  EOI_T1                     ; Nein, fertig
	                                 ; Ja
	sbr temp1, W_Taste_ON	         ; Merker "Taste gedr�ckt"

    CLR_CNT_STEP:                    ; Clear Counter Step
  ; --------------------------------
    andi temp1, 0xF0
	rjmp  EOI_T1                    ; Nein, fertig

    Step_10_entprellen:              ; Entprellen 1 nach 0. Taste wird losgelassen
  ; --------------------------------
	sbis  PINB, Taster               ; Taste gedr�ckt ?
    rjmp CLR_CNT_STEP                ; Ja. CNT_Z�hler l�schen
    inc temp1                        ; Nein. CNT erh�hen. Low Pegel z�hlen
	sbrs temp1, CNT_3                ; Z�hlerende erreicht ?
	rjmp  EOI_T1                     ; Nein, fertig
    cbr temp1, W_Taste_ON            ; Ja. Taste zur�cksetzen

    andi temp1, 0xF0                 ; Clear Counter Step

 EOI_T1:

    mov CNT_Step, temp1              ; Store CNT_Step
    pop temp1
    out SREG,temp1

	pop temp3
    pop temp2
	pop temp1
	reti

; ************************************************************

Ich verlinke für alle mal das DAC-Datenblatt, ok?

Ich habe mir bis jetzt weder das Programm, noch das DB genauer angesehen, aber trotzdem schonmal einige Kommentare:
  • Ich(!) sehe keinen Sinn darin, die IVT mit RETIs zu füllen, aber das ist Deine Sache - ich weiß, daß das Thema FlameWarPotenzial hat
  • Den Stackpointer brauchst Du bei diesem Controller auch nicht zu initialisieren, der ist bereits default RAMEND
  • Du verwendest R27..R25 als generelle temporäre Register. Für Immediate-Operationen sollen es Register ab R16 sein, aber die Register ab R24 können für 16bit-Operationen verwendet werden, teilweise auch als 16bit-Pointer (zB für indirekte Speicherzugriffe und Sprünge).
  • max. SPI-Clock: Als Slave sampelt der AVR die SCK Leitung und benötigt mindestens 2 Takte pro Phase - effektiv sind also höchstens FCPU/4 Taktfrequenz drin.
    Als Master erzeugt der AVR den SCK-Takt, hier kannst Du (mit SPI2X) maximal FCPU/2 vorgeben
Grüße
LotadaC
 
Hallo Gottfried,

im Code habe ich keinen Fehler finden können. Die Subtraktionen laufen korrekt und die neuen Werte werden ja dann immer wieder die gleiche Art gesendet, wie 0 und 4095. Mir erschließt sich erstmal nicht, was da los ist.

Wie sieht es denn aus mit den grundlegenden Kleinigkeiten wie Abblockkondensator und Pullup am RESET ?

Dass der MCP die Daten mit steigender Flanke einliest, ist für mich nicht ungewöhnlich. Das kenne ich von anderen IC's auch. Hast du einen LA, um die Datensendung zu überprüfen ?
Ansonsten könntest du das Senden der Daten mal testweise "manuell", also per Programm realisieren. Wenn es dann läuft, liegt das Problem bei der Hardware des ATMega oder deren Konfiguration.

Gruß
Pirx
 
Wenn da nicht gerade 'ne Kapazität und 'ne lange Antenne am Reset hängen, brauchts da keinen externen Pullup - der interne beträgt irgendwo zwischen 20 und 50 Kiloohm...

Abblockkerkos an allen Stromversorgungspaaren sind natürlich empfehlenswert, ggf ein kleiner Pufferelko für alles.
So, wie ich Gottfried verstanden hatte, sieht er die korrekten (gesendeten) Signale auf dem Bus mit 'nem Oszi...

Wenn er den einen DAC-Kanal sauber geregelt bekommt, sollte die Kommunikation selbst stimmen, wenn nur der 2te nicht reagiert (und das Teil nicht defekt ist), kann ja eigentlich nur noch irgendwas im Protokoll nicht passen...

Wie Pirx schon angedeutet hat: Schreib doch mal ein Testprogramm, das nur Kanal A, nur Kanal B mit vorgegebenen Werten beschreibt, und arbeite dann in langsamen Schritten auf Dein eigentliches Ziel hin...
 
Hallo Gottfried,

ich hab mir den Code nun nicht angesehen :eek: aber im Datenblatt hab ich ein paar Stolperstellen gefunden die einen schnell zu Fall bringen könnten ...

Seite 21:
5.2 Write Command
...
All writes to the MCP4802/4812/4822 devices are 16-bit words. Any clocks after the first 16th clock will be ignored. The Most Significant four bits are Configuration bits. The remaining 12 bits are data bits. No data can be transferred into the device with CS high.
...
Wenn man also versucht 32Bit für die beiden Kanäle hintereinander einzutakten klappt das nicht. Man muß beide Kanäle getrennt übertragen.
/CS auf Low, 4 Control-Bits, 12 Datenbits Kanal 1, /CS High, /CS Low, 4 Control-Bits, 12 Datenbits Kanal 2, /CS High

Wenn es mit 0 und 4095 auf beiden Kanälen funktioniert,dann sollte das aber auch gehen :confused: komisch.

Eventuell nen Timingproblem beim SPI-Takt? Wenn Mode 0,0 und 1,1 möglich ist, dann würde ich da mal was probieren. In nem anderen Thread hatten wir das mal mit dem SPI-Takt. Da hat der Slave grade noch so die Bits mitbekommen. Manchmal ging es aber auch mit einigen oder sogar allen Bits schief.

Auf Seite 7 ist noch ein Timing-Diagramm der Kommunikation zwischen zwei Datenpaketen. tCSH muß dabei mindestens 15ns High zwischen den Datenpaketen sein. Das sollte eigentlich selbst bei 20MHz Taktfrequenz passen. Da wären dann keine kürzeren Zeiten als 50ns möglich. ... alles recht komisch :confused:

Haut da in die zweite Kommunikation irgendwas rein? Nen Interrupt? Also ich tippe stark auf nen Timingproblem bei der zweiten Kommunikation oder aber das du bei dem Programmteil das dann mit dem Taster die Werte verringert einfach irgendwie das Kanalbit nicht umschaltest und zweimal auf den ersten Kanal überträgst.

Gruß
Dino
 
Ich finde das ganze zusammensetzen der beiden Bytes ein wenig "von hinten durch die Brust ins Auge":
  • Die eigentlichen Werte werden aus einem Register in die Temp-Register kopiert
  • Mittels ANDI wird das oberste Nibble gelöscht
  • Mittels SBR werden die Steuerbits in diesem Nibble wieder gesetzt
  • Aufruf der Senderoutine
  • anschließend (ebenfalls mit hin und herkopieren) werden die Werte in den "Speicherregistern" verringert
Wenn die Werte eh schon in den Registern stehen, warum dann nicht gleich die Register mit immediate-Zugriff?
Wie ist das mit SHDN=0? damit sollte der Kanal doch jedesmal in den Standby geschickt werden, oder?
 
Hi,

ich hab mal ein wenig im Programm gelesen ...

Bei deiner Senderoutine würde ich noch folgendes machen ...
Code:
    SPI_Out:

       cbi   SPI_PORT, SPI_SS          ; CS auf L startet �bertragung zum DAC
       nop                                   ; Timing entspannen <=======
       out   SPDR, temp1
Laut dem Datenblatt muß zwischen /CS auf Low und erstem Sendetakt mindestens 40ns Zeit sein. Der eine NOP sollte an der Stelle das Timing ein wenig entspannen. Sollte auch ohne NOP passen ... aber man weiß ja nie :rolleyes:

Sonst sehe ich erstmal nichts was sofort ins Auge fällt.

Gruß
Dino
 
Jetzt geht es.

Servus zusammen.

der Hinweis mit dem SHDN=0 hat mich auf die richtige Spur gebracht. Danke LotadaC und allen, die mir geantwortet haben.
Ich hab das so interpretiert, dass SHDN=1 den DAC schlafen legt und ein erneutes senden von Daten ihn wieder aktiviert.
Es ist aber so, dass SHDN=0 den DAC wohl schlafen und eine 1 ihn wieder weckt. Warum er trotzdem auf Kanal B empfangen hat
ist mir unklar. Verstanden hab ich die Bedeutung von SHDN nicht 100%ig.
Ich finde das ganze zusammensetzen der beiden Bytes ein wenig "von hinten durch die Brust ins Auge":
Ja. Aber der Code ist nur ein kleiner Teil vom Gesamtcode. Eben nur der Teil, der den DAC ansteuert. ANDI sollte das obere Nipple löschen, falls bei der Berechnung was nicht stimmt. Dann würde es mir die Steuerbits verkehrt setzen.
Meine oberen 16 Register sind alle belegt. Da der DAC weniger oft beschrieben wird hab ich die unteren Register mit den Varialben belegt. Das Hauptprogramm berechnet den Wert und legt ihn erstmal ab. Wenn ein bestimmtes Ereignis eintritt, holt sich ein anderer Programmteil den Wert und gibt ihn aus.
Wie Pirx schon angedeutet hat: Schreib doch mal ein Testprogramm, das nur Kanal A, nur Kanal B mit vorgegebenen Werten beschreibt, und arbeite dann in langsamen Schritten auf Dein eigentliches Ziel hin... .
Hab ich gemacht, und das hat mich dann letztendlich auch auf die richtige Spur gebracht. Danke Pirx.
Abblockkerkos an allen Stromversorgungspaaren sind natürlich empfehlenswert
100nF Kondensatoren hab ich immer an allen pos. und neg. Spannungsversorgungen dran. Auch an AVcc. Reset geht mit 12k gegen Vcc.
ich finde es besser, wenn der code hier in lesbarer Form (in Code-Tags) steht -
Wollte ich, hab es aber nicht kapiert wie das geht. Wohl über "#" Code einfügen oben rechts.:eek::eek:
•Ich(!) sehe keinen Sinn darin, die IVT mit RETIs zu füllen, aber das ist Deine Sache - ich weiß, daß das Thema FlameWarPotenzial hat
Hab ich so von woanderst kopiert. Sag mir bitte wie es eleganter geht. Ich bin immer lehrfähig. Besonders, wenn es das Leben einfacher macht.
•Du verwendest R27..R25 als generelle temporäre Register. Für Immediate-Operationen sollen es Register ab R16 sein, aber die Register ab R24 können für 16bit-Operationen verwendet werden, teilweise auch als 16bit-Pointer (zB für indirekte Speicherzugriffe und Sprünge).
Es sind im Moment nur noch R27/28 frei. Die anderen beiden 16Bit Register verwende ich um aus Tabellen zu lesen. Temp3 ist aber momentan gar nicht in gebrauch. Kann ich bei Bedarf ersetzen.
Hier nun der neue neue Code :

Code:
/* ext Oszillator 20MHz


; CLKDIV8

; CK = 8MHz 

; => Fuse_low = ........ = 0xxx
; => Fuse_High =........ = 0xxx




*/
.include "G:\m328Pdef.inc"



; ***** INTERRUPT VECTORS ************************************************
.org 0x0000
  rjmp Init ; RESET 
.org 0x0002	; External Interrupt Request 0
  reti 
.org 0x0004	; External Interrupt Request 1
  reti 
.org 0x0006	; Pin Change Interrupt Request 0
  reti 
.org 0x0008	; Pin Change Interrupt Request 0
  reti 
.org 0x000a	; Pin Change Interrupt Request 1
  reti 
.org 0x000c	; Watchdog Time-out Interrupt
  reti 
.org 0x000e	; Timer/Counter2 Compare Match A
  reti 
.org 0x0010	; Timer/Counter2 Compare Match A
  reti 
.org 0x0012	; Timer/Counter2 Overflow
  reti 
.org 0x0014	; Timer/Counter1 Capture Event
  reti
.org 0x0016	; Timer/Counter1 Compare Match A
  reti
.org 0x0018	; Timer/Counter1 Compare Match B
  reti
.org 0x001a	; Timer/Counter1 Overflow
  reti
.org 0x001c	; TimerCounter0 Compare Match A
  reti 
.org 0x001e	; TimerCounter0 Compare Match B
  reti 
.org 0x0020	; Timer/Couner0 Overflow
  rjmp TIM0_OVF 
.org 0x0022	; SPI Serial Transfer Complete
  reti 
.org 0x0024	; USART Rx Complete
  reti 
.org 0x0026	; USART, Data Register Empty
  reti 
.org 0x0028	; USART Tx Complete
  reti 
.org 0x002a	; ADC Conversion Complete
  reti 
.org 0x002c	; EEPROM Ready
  reti 
.org 0x002e	; Analog Comparator
  reti 
.org 0x0030	; Two-wire Serial Interface
  reti 
.org 0x0032	; Store Program Memory Read
  reti 

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.def CNT_Step     = R9   ; dient zum Entprellen des Tasters
.def CV_A_H       = R10  ; DAC Wert für WaveShape
.def CV_A_L       = R11  ; DAC Wert für WaveShape
.def CV_B_H       = R12  ; DAC Wert für PWCV
.def CV_B_L       = R13  ; DAC Wert für PWCV

.def temp1        = R25  ; Zwischenspeicher allgemein 
.def temp2        = R26  ; Zwischenspeicher allgemein 
.def temp3        = R27  ; Zwischenspeicher allgemein 

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    .equ CNT_0            = 0     ;  
    .equ CNT_1            = 1     ;
	.equ CNT_2            = 2     ;
	.equ CNT_3            = 3     ;
	.equ CNT_4            = 4     ;
	.equ Merker_Input     = 5     ;
	.equ Merker_Taste     = 6     ;
	.equ Taste_ON         = 7     ;

    .equ W_CNT_0          = 0x01    ;
    .equ W_CNT_1          = 0x02    ;
	.equ W_CNT_2          = 0x04    ;
	.equ W_CNT_3          = 0x08    ;
	.equ W_CNT_END        = 0x10    ;
	.equ W_Merker_Input   = 0x20    ;
	.equ W_Merker_Taste   = 0x40    ;
	.equ W_Taste_ON       = 0x80    ;

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 INIT:

    ldi temp1, LOW(RAMEND)
    out SPL, temp1
    ldi temp1, HIGH(RAMEND)
    out SPH, temp1

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 Timer0 normal mode

 CS02 | CS01 | CS00     Description
  0       0      0      No clock source (Timer/Counter stopped)
  0       0      1      No prescaling
  0       1      0      clk  /8 (From prescaler)
  0       1      1      clk  /64 (From prescaler)
  1       0      0      clk  /256 (From prescaler)
  1       0      1      clk  /1024 (From prescaler)
  1       1      0      External clock source on T0 pin. Clock on falling edge.
  1       1      1      External clock source on T0 pin. Clock on rising edge.

*/
	ldi temp1, 0<<CS00 | 1<<CS01 | 0<<CS02
	out TCCR0B, temp1


	; Timer0 Overflow Interrupt enable
	ldi temp1, (1<<TOIE0)
	sts TIMSK0, temp1
    

	sei

/* ************************************************************    
  
    ; SPI einrichten


    Konfigurierung DAC MCP4822
    -------------------------------------------------------------------------------------------
    bit 15 A/B: DACA or DACB Select bit | bit 14          | bit 13 GA: Output Gain Select bit |
    1 = Write to DACB                   | Don’t Care      | 1 = 1x (VOUT = VREF * D/4096)     |
    0 = Write to DACA                   |                 | 0 = 2x (VOUT = 2 * VREF * D/4096) |
    ------------------------------------------------------|-----------------------------------|
    bit 12 SHDN: Output Power-down Control bit            | bit 11-0 D11:D0: DAC Data bits    |
    1 = Output Power-down Control bit                     |                                   |
    0 = Output buffer disabled, Output is high-impedance  |                                   |
    -------------------------------------------------------------------------------------------
*/


.equ SPI_DDR      = DDRB
.equ SPI_PORT     = PORTB
.equ LED          = PB0
.equ Taster       = PB1
.equ SPI_SS       = PB2
.equ SPI_MOSI     = PB3
.equ SPI_MISO     = PB4
.equ SPI_CLK      = PB5 
.equ Select       = 7
.equ Vref         = 5
.equ SHDN         = 4

;    Konfigurierung DAC MCP4822
;    LDAC liegt an GND

    in    temp1, SPI_DDR
    ori   temp1 , 1<<SPI_SS
    out   SPI_DDR,  temp1   ; DDRB

    in    temp1, SPI_DDR
    ori   temp1 , 1<<SPI_CLK | 1<<SPI_MOSI | 1<<Led | 0<<Taster
    out   SPI_DDR,  temp1   ; DDRB

	ldi   temp1, (1<<SPE) | (1<<MSTR) | (0<<DORD) | (0<<SPR0) | (1<<CPOL) | (1<<CPHA)
    out   SPCR, temp1

	ldi   temp1, (1<<SPI2X)              ;1= double speed aktivieren
    out   SPSR, temp1

    cbi SPI_PORT, SPI_SS                 ; DAC CS auf H = keine Übertragung


; ************************************************************   

    .equ DACA = 0b00110000
    .equ DACB = 0b10110000

    clr temp1
    clr temp2


    ldi temp1, 0b00100000
    ldi temp2, 0x00
    rcall SPI_Out
    in    temp1, SPDR

    ldi temp1, 0b10100000
    ldi temp2, 0x00
    rcall SPI_Out
    in    temp1, SPDR


  Set_CV:

    .equ CV_A = 2500
    .equ CV_B = 3800

    ldi temp1,  HIGH (CV_A)
    mov CV_A_H, temp1
    ldi temp1,  LOW (CV_A)
    mov CV_A_L, temp1

    ldi temp1,  HIGH (CV_B)
    mov CV_B_H, temp1
    ldi temp1,  LOW (CV_B)
    mov CV_B_L, temp1

 main:

    sbi SPI_PORT, Led                   ; Led ausschalten.



    Warte1_auf_Taster:
    sbrs CNT_Step, Taste_ON             ; Taster gedrückt ?
    rjmp Warte1_auf_Taster              ; Nein. => Warten

    cbi SPI_PORT, Led                   ; Led einschalten.

    mov   temp1, CV_A_H
    mov   temp2, CV_A_L
    ori   temp1, DACA                   ; DAC Kanal A
    rcall SPI_Out	                    ; CV ausgeben
	in    temp1, SPDR                   ; SPIF löschen 

    mov   temp1, CV_B_H
    mov   temp2, CV_B_L
    ori   temp1, DACB                   ; DAC Kanal B
    rcall SPI_Out                       ; CV ausgeben
    in    temp1, SPDR 

; CV-WERT A um 128 verringern.

	mov   temp1, CV_A_L
	mov   temp2, CV_A_H
	cpi   temp2, 0x00
    breq  Set_CV                       ; Wert = 0. Maximalwerte holen
    subi  temp1, 0x80                  ; subtrahieren
    sbci  temp2, 0x00
	mov   CV_A_L, temp1                ; zurückspeichern
	mov   CV_A_H, temp2

; CV-WERT B um 128 verringern.

	mov   temp1, CV_B_L
	mov   temp2, CV_B_H
    subi  temp1, 0x80                  ; subtrahieren
    sbci  temp2, 0x00
	mov   CV_B_L, temp1                ; zurückspeichern
	mov   CV_B_H, temp2

    Warte2_auf_Taster:
    sbrc CNT_Step, Taste_ON            ; Taster gedrückt ?
    rjmp Warte2_auf_Taster             ; Ja. => Warten

    rjmp main

; ************************************************************

    SPI_Out:
       ;cli
       cbi   SPI_PORT, SPI_SS          ; CS auf L startet Übertragung zum DAC
	   nop
       out   SPDR, temp1

       Wait_WS_1:                      ;  Wait for tx complete	
	   in    temp1, SPSR
       sbrs  temp1, SPIF      
       jmp   Wait_WS_1

       out   SPDR, temp2 

	Wait_WS_2:                         ;  Wait for tx complete	
	   in    temp1, SPSR
       sbrs  temp1, SPIF      
       jmp   Wait_WS_2
       

    ;  Übertragung fertig
       nop
	   sbi   SPI_PORT, SPI_SS          ; CS auf H beendet Übertragung zum DAC
     ;sei
     ret

; ************************************************************

    TIM0_OVF:

    push temp1                        ; Register 1 reten
	push temp2                        ; Register 2 reten
	push temp3                        ; Register 3 reten

    in temp1, SREG                    ; Status-Register reten
    push temp1

 ; --------------------------------
  ; Steptaster entprellen
  ; --------------------------------
    Test_Step:

    mov temp1, CNT_Step              ; Zähler für die Entprellung holen
	sbrc temp1, Taste_ON             ; Taste bereits ON ?
    rjmp Step_10_entprellen          ; ja. Entprellen 1 nach 0. Taste wird losgelassen

    Step_01_entprellen:              ; Entprellen 0 nach 1. Taste wird gedrückt
  ; --------------------------------
	
	sbic  PINB, Taster               ; Taste gedrückt
    rjmp  CLR_CNT_STEP               ; Nein. Clear Counter Step. Keine Entprellung
    
    inc temp1                        ; Ja. CNT erhöhen. H-Pegel zählen
	sbrs temp1, CNT_3                ; Zählerende erreicht ?
    rjmp  EOI_T1                     ; Nein, fertig
	                                 ; Ja
	sbr temp1, W_Taste_ON	         ; Merker "Taste gedrückt"

    CLR_CNT_STEP:                    ; Clear Counter Step
  ; --------------------------------
    andi temp1, 0xF0
	rjmp  EOI_T1                    ; Nein, fertig

    Step_10_entprellen:              ; Entprellen 1 nach 0. Taste wird losgelassen
  ; --------------------------------
	sbis  PINB, Taster               ; Taste gedrückt ?
    rjmp CLR_CNT_STEP                ; Ja. CNT_Zähler löschen
    inc temp1                        ; Nein. CNT erhöhen. Low Pegel zählen
	sbrs temp1, CNT_3                ; Zählerende erreicht ?
	rjmp  EOI_T1                     ; Nein, fertig
    cbr temp1, W_Taste_ON            ; Ja. Taste zurücksetzen

    andi temp1, 0xF0                 ; Clear Counter Step

 EOI_T1:

    mov CNT_Step, temp1              ; Store CNT_Step
    pop temp1
    out SREG,temp1

	pop temp3
    pop temp2
	pop temp1
	reti

; ************************************************************

Danke nochmal an alle
Werde den Code nun so ins Programm übernehmen. Da läuft es dann mit einem ext. 20Mhz Quarz. Bin gespannt.

Gruß

Gottfried
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)