Benutzer-Werkzeuge

Webseiten-Werkzeuge


Writing /srv/www/htdocs/udo/singollo.de/linux.singollo.de/public_html/data/cache/1/1fb1c61142f0c3c539b0cf2372a4307a.metadata failed
hardware:lcd_ea_dog_m162_und_atmega8_spi

EA DOG-M 162 und ATMega8 mit SPI

Bei den ganzen Versuchen mit der 4 Bit-Ansteuerung des EA DOG-M 162 und einem Drehencoder bin ich immer wieder auf Schwierigkeiten gestossen. Zwar reichen die Ports des Mega8 für meine Versuche aus, aber ich wollte nicht einen ganzen Port verschenken. So habe ich lange mit dem Gedanken gespielt, die Ansteuerung auf SPI umzustellen. Allerdings hatte ich einige Verständnisprobleme zu meistern. Nach einigem Suchen fand ich bei http://www.mikrocontroller.net/ ein gut verständliches Stück Code in C geschrieben von Christopher Müller. Da ich allerdings die Megas in Assembler programmiere, musste ich da noch bisschen stöbern. In den App-Notes von Atmel fand ich dann den passenden Zugang und ich konnte die erste Umsetzung angehen. Gleich der erste Versuch glückte, jedoch war alles etwas sehr träge. Das kannte ich so nicht von der 4 Bit-Version. Also musste im Code noch ein Fehler liegen. An der Initialisierung lag es jedenfalls nicht, die war aus dem Datenblatt entnommen. Nach einigen Fehlversuchen nahm ich nochmal das Datenblatt zur Hand und fand in der Tabelle des Instructioncodes auch Timingangaben. Das wars! Die Timingangaben waren irgendwie fehlerhaft. Bis auf zwei Befehle führt der Displaycontroller alle deutlich unter 30µs aus. Also alle Delays abgeändert und schon funktionierte es wie gewünscht!

Fuses

  • High: 0xC6
  • Low: 0x7E

Das entspricht den gesetzen Fuses: EESAVE, BOOTSZ (size=128, address=$0F80), BOOTRST, CKOPT, SUT_CKSEL (Ext. High Freq 1k CK+4ms). Brown-out ist abgeschaltet, keine Lock-Bits gesetzt.

Schaltung

Ich habe das Display gemäß Datenblatt im 5V-SPI-Modus angeschlossen. Dabei wird die SPI-Schnittstelle wie folgt mit dem Mega8 verbunden:

  • PB3 (Pin 17, MOSI) → SI (Pin 28)
  • PB5 (Pin 19, SCK) → CLK (Pin 29)
  • PB1 (Pin 15) → CSB (Pin 38)
  • PB2 (Pin 16) → RS (Pin 39)
  • PC3 (Pin 26) → Backlight (über Logik-MOSFET geschaltet)

Alle Portpins müssen als Ausgang geschaltet werden. Der µC ist als Master tätig. Es wird ein 16MHz-Quarz Typ HC49U-S eingesetzt.

Ich werde noch einen passenden Schaltplan als Grafik nachliefern.

Listing 1: main.asm

.include "m8def.inc"
 
.ifndef XTAL
.equ XTAL	= 16000000
.endif
 
.def temp1	= r16
.def temp2	= r17
.def temp3	= r18
 
.cseg
 
.org 0x0000
    rjmp    main				; Reset Handler
 
main:
	; Stackpointer initialisieren
	ldi     temp1, HIGH(RAMEND)
	out     SPH, temp1
	ldi     temp1, LOW(RAMEND)     
	out     SPL, temp1
 
	rcall	lcd_init			; Display initialisieren
 
	ldi	ZL,LOW(boot*2)
	ldi	ZH,HIGH(boot*2)
	rcall	lcd_flash_string		; Gibt Begrüßung aus
 
	ldi	temp3, 250
	rcall	_delay_ms
	ldi	temp3, 250
	rcall	_delay_ms
	ldi	temp3, 250
	rcall	_delay_ms
	ldi	temp3, 250
	rcall	_delay_ms
 
 	rcall	lcd_clear
 
	ldi	ZL,LOW(text*2)
	ldi	ZH,HIGH(text*2)
	rcall	lcd_flash_string		; Gibt Begrüßung 2 aus
 
main_loop:
	rjmp	main_loop
 
.include "lcd_spi.asm"
.include "delay.asm"
 
boot: 
.db "Booting..",0				; Welcome
 
text:
.db "Hello",0					; Welcome

Listing 2: lcd_spi.asm

.equ DDR_SPI	= DDRB
.equ DD_MOSI	= DDB3
.equ DD_SCK	= DDB5
.equ DD_RS	= DDRB
.equ PORT_RS	= PORTB
.equ PIN_RS	= PB2
.equ DD_CSB	= DDRB
.equ PORT_CSB	= PORTB
.equ PIN_CSB	= PB1
.equ DD_BL	= DDRC
.equ PORT_BL	= PORTC
.equ PIN_BL	= PC3
 
; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
lcd_init:
	ldi	temp1,(1<<DD_MOSI)|(1<<DD_SCK)
	out	DDR_SPI,temp1			; MOSI und SCK als Ausgang
 
	ldi	temp1,(1<<SPE)|(1<<MSTR)
	out	SPCR,temp1			; SPI, Master und fck/4
 
	in	temp1,DD_BL
	sbr	temp1,(1<<PIN_BL)		; Backlight als Ausgang
	out	DD_BL,temp1
	rcall	backlight_off			; Backlight off
 
	in	temp1,DD_CSB
	sbr	temp1,(1<<PIN_CSB)		; CSB als Ausgang
	out	DD_CSB,temp1
	cbi	PORT_CSB, PIN_CSB		; CSB auf LOW
 
	in	temp1,DD_RS
	sbr	temp1,(1<<PIN_RS)		; RS als Ausgang
	out	DD_RS,temp1
	cbi	PORT_RS, PIN_RS			; RS auf LOW
 
	in	temp1,DD_BL
	sbr	temp1,(1<<PIN_BL)		; RS als Ausgang
	out	DD_BL,temp1
 
	ldi	temp3,50
	rcall 	_delay_ms			; 50ms warten
 
	ldi	temp1,0b00111001		; 8-Bit, 2 Zeilen, Instruction Table 1
	rcall	lcd_command
	ldi	temp1,0b00010100		; Bias 1/4, 2 Zeilen
	rcall	lcd_command
	ldi	temp1,0b01010010		; Booster aus, Kontrast C5/C4 setzen
	rcall	lcd_command
	ldi	temp1,0b01101001		; Follower setzen
	rcall	lcd_command
	ldi	temp1,0b01110100		; Kontrast C3/C2/C1/C0 setzen
	rcall	lcd_command
	ldi	temp1,0b00111000		; Instruction Table 0
	rcall	lcd_command
	ldi	temp1,0b00001100		; Display on, Cursor off, Cursor not blinking
	rcall	lcd_command
	rcall	lcd_clear
	rcall	lcd_home
	ldi	temp1,0b00000110		; Autoincrement
	rcall	lcd_command
	rjmp	backlight_on			; Backlight ein
 
; Sendet ein Datenbyte an das LCD
lcd_data:
	sbi	PORT_RS, PIN_RS			; RS auf HIGH
	out	SPDR,temp1			; Datum in SPI-Ausgangsregister
lcd_data_wait:
	sbis	SPSR,SPIF			; Warten bis gesendet
	rjmp	lcd_data_wait
	cbi	PORT_RS, PIN_RS			; RS auf LOW
	sbi	PORT_RS, PIN_RS			; RS auf HIGH
 
	rjmp 	_delay_30us			; 30µs warten
 
 
; Sendet einen Befehl an das LCD
lcd_command:
	cbi	PORT_RS, PIN_RS			; RS auf LOW
	out	SPDR,temp1			; Datum in SPI-Ausgangsregister
lcd_command_wait:
	sbis	SPSR,SPIF			; Warten bis gesendet
	rjmp	lcd_command_wait
	sbi	PORT_RS, PIN_RS			; RS auf HIGH
	cbi	PORT_RS, PIN_RS			; RS auf LOW
 
	rjmp 	_delay_30us			; 30µs warten
 
;
; Displaybefehle
;
 
; Sendet den Befehl zur Löschung des Displays
lcd_clear:
	ldi	temp1, 0b00000001		; Display löschen
	rcall	lcd_command
	rjmp 	_delay_1ms			; 1ms warten
 
; Cursor Home
lcd_home:
	ldi	temp1, 0b00000010		; Cursor Home
	rcall	lcd_command
	rjmp 	_delay_1ms			; 1ms warten
 
; Cursor 1. Zeile
lcd_firstrow:
	ldi	temp1, 128			; Cursor 1. Zeile
	rjmp	lcd_command
 
; Cursor 2. Zeile
lcd_secondrow:
	ldi	temp1, 192			; Cursor 2. Zeile
	rjmp	lcd_command
 
; Eine Zahl aus dem Register temp1 dezimal ausgeben
lcd_number:
	push	temp2				; Register sichern,
						; wird für Zwsichenergebnisse gebraucht     
	ldi	temp2, '0'         
lcd_number_10:                
	subi	temp1, 10			; abzählen wieviele Zehner in
	brcs	lcd_number_1			; der Zahl enthalten sind
	inc	temp2
	rjmp	lcd_number_10
lcd_number_1:
	push	temp1				; den Rest sichern (http://www.mikrocontroller.net/topic/172026)
	mov	temp1,temp2 
	rcall	lcd_data			; die Zehnerstelle ausgeben
	pop	temp1				; den Rest wieder holen
	subi	temp1, -10			; 10 wieder dazuzählen, da die
						; vorhergehende Schleife 10 zuviel
						; abgezogen hat
						; das Subtrahieren von -10
						; = Addition von +10 ist ein Trick
						; da kein addi Befehl existiert
	ldi	temp2, '0'			; die übrig gebliebenen Einer
	add	temp1, temp2			; noch ausgeben
	rcall	lcd_data
 
	pop	temp2				; Register wieder herstellen
	ret
 
; Eine Zahl aus dem Register temp1 hexadezimal ausgeben
lcd_number_hex:
	push	temp1
	swap	temp1
	andi	temp1, $0F
	rcall	lcd_number_hex_digit
	pop	temp1
	push	temp1
	andi	temp1, $0F
	rcall	lcd_number_hex_digit
	pop	temp1
	ret
lcd_number_hex_digit:
	cpi	temp1, 10
	brlt	lcd_number_hex_digit_1
	subi	temp1, -( 'A' - '9' - 1 )
lcd_number_hex_digit_1:
	subi	temp1, -'0'
	rcall	lcd_data
	ret
 
; Einen konstanten Text aus dem Flash Speicher
; ausgeben. Der Text wird mit einer 0 beendet
lcd_flash_string:
	push	temp1
	push	ZH
	push	ZL
lcd_flash_string_1:
	lpm	temp1, Z+
	cpi	temp1, 0
	breq	lcd_flash_string_2
	rcall	lcd_data
	rjmp	lcd_flash_string_1
lcd_flash_string_2:
	pop	ZL
	pop	ZH
	pop	temp1
	ret
 
backlight_on:
	sbi	PORT_BL, PIN_BL			; Backlight H = On
	ret
backlight_off:
	cbi	PORT_BL, PIN_BL			; Backlight L = Off
	ret

Listing 3: delay.asm

Es werden einige Delays benötigt. Damit die nicht irgendwo in den verschiedenen Codeteilen verteilt sind, habe ich diese in eine eigene Datei ausgelagert.

;
; Verzögerungsschleifen
;
 
; _delay_30us: 30us Pause
_delay_30us:
	push	temp1
	ldi	temp1, ( XTAL * 30 / 3 ) / 1000000
_delay_30us_loop:
	dec	temp1
	brne	_delay_30us_loop
	pop	temp1
	ret
 
; _delay_1ms: 1ms Pause
_delay_1ms:
	push	temp1
	push	temp2
	ldi	temp1, ( XTAL / 607 ) / 1000
_delay_1ms_loop0:
	ldi	temp2, $C9
_delay_1ms_loop1:
	dec	temp2
	brne	_delay_1ms_loop1
	dec	temp1
	brne	_delay_1ms_loop0
	pop	temp2
	pop	temp1
	ret
 
; _delay_ms: x ms Pause
; Register: temp3
_delay_ms:
	rcall 	_delay_1ms
	dec	temp3
	brne	_delay_ms
	ret
hardware/lcd_ea_dog_m162_und_atmega8_spi.txt · Zuletzt geändert: 07.10.2012 18:31 (Externe Bearbeitung)