[ASM] DOGM132x-5 over SPI on ATmega8820AU

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys!

I'm not sure if I'm having problems with SPI in general or "just" with the Display (DOGM132x-5) - either way, it doesn't display anything at all. I'm using the ATmega 8820AU (set the AVR Assembler to ATmega88, Assembler 2).

I hooked it up with 9 capacitors like in the datasheet example for "wide range" input, supply it with 3.3V

I connected these AVR pins and DOGM pins:

GND - dogCS1B
PB0 - dogRS
PB1 - dogA0
MOSI - dogSI
SCK - dogSCL

I set the SPI to CPOL=1, CPHA=1, Freq: /4
The µC clocks with 9,6MHz.

For sending data to the display, I RCALL this procedure (setting acc to the value being about to send before - acc is R16):

spi_send:
  OUT SPDR, acc
  spi_send_wait:
  IN acc, SPSR
  SBRS acc, SPIF
  RJMP spi_send_wait
  RET

which runs into an endless loop. So I changed it to:

spi_send:
  OUT SPDR, acc
  NOP (well over 40 times, tried with a lot more too)
  RET

which does run without an endless loop and should give enough time for SPI to send a byte successfully. Let's call it a debugging hack.

First, I pull dogmRS to GND, then to Vcc. The commands (A0=0) I send for initialization are these:

0b01000000 // start line set
0b10100000 // adc select
0b11001000 // common output mode select
0b10100110 // display normal/reverse
0b10100010 // lcd bias set
0b00101111 // power control
0b11111000 // booster ratio
0b00000000 // booster ratio, continued
0b00100011 // contrast
0b10000001 // contrast, continued
0b00011111 // contrast, continued
0b10101100 // static indicator
0b10101111 // display on

And then I try sending a character (80 = "P") to the display (A0=1).

And well, it does exactly nothing.

Some initialization that's happening before the above:

.DEF acc = R16 // accumulator 1

LDI acc, 0b00101011 // xtal,xtal,SCL,miso,SI,ss,A0,RS
OUT DDRB, acc
LDI acc, 0b00000000 // clear outputs, disable all pullups
OUT PORTB, acc

LDI acc, 0b11011100 // SPI master, prescaler 4
OUT SPCR, acc
LDI acc, 0b00000000 // no 2x speed
OUT SPSR, acc

SEI

There's no endless loop, I have LEDs connected and light them once all code has run - they are on.

Can anyone here help me a little? I'm stuck and don't have a clue where to look. The forum search for dogm132* shows zero results, google isn't of great help either - and the datasheets don't give me much information.

Datasheet (display, very brief, in german):
http://www.lcd-module.de/deu/pdf...
Datasheet (display controller, in english):
http://www.lcd-module.de/eng/pdf...

Thanks for any help!
Markus

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what I've used for DOGM 128*64
Init sequence:

time_init:	
	ldi	ctr,120 		;set up DELAY            			
init_del:	
	rcall	delay_1ms		;INIT DELAY 120 ms
	dec	ctr			;dec ctr
	brne	init_del		;until zero
lcd_init:
	cbi	portd,rst		;release LCD reset
	rcall	delay_1ms		;reset delay 1ms
	sbi	portd,rst		;release LCD reset
	rcall	delay_1ms		;reset delay 1ms
	ldi	data,line		;set StartLine0 (0x40)	
	call	lcd_cmd		;for LCD
	ldi	data,0xa1		;AdcReverse View
	call	lcd_cmd		;AdcNormal View = 0xA0
	ldi 	data,0xc0		;Normal COM0-COM63
	call	lcd_cmd		;LCD instruction
	ldi	data,0xa6		;Display normal lit/unlit
	call	lcd_cmd		;Inverted display = 0xA7
	ldi	data,0xa2		;Set Bias 1/9 (Duty 1/65)
	call	lcd_cmd		;LCD instruction
	ldi	data,0x2f		;Booster,Reg,Follower ON
	call	lcd_cmd		;and character fonts of LCD
	ldi	data,0xf8		;Msb Booster 4x
	call	lcd_cmd		;LCD instruction
	ldi 	data,0x00		;Lsb Booster 4x
	call	lcd_cmd		;LCD instruction
	ldi	data,0x27		;V0 Regulator set
	call	lcd_cmd		;LCD instruction
	ldi	data,0x81		;Msb Electronic Volume
	call	lcd_cmd		;LCD instruction
	ldi	data,0x10		;Lsb Electronic Volume
	call	lcd_cmd		;LCD instruction
	ldi 	data,0xac		;Msb Indicator Off
	call	lcd_cmd		;LCD instruction
	ldi	data,0x00		;Lsb Indicator Off
	call	lcd_cmd		;LCD instruction
	ldi	data,0xaf		;Display ON
	call	lcd_cmd		;LCD instruction
	call	blank_screen	;BLANK SCREEN

And for sending Commands and Data:

lcd_cmd:
	cbi	portd,a0		;LCD COMMAND	
	rjmp	write_all		;write COMMAND
		
lcd_data:
	sbi	portd,a0		;LCD DATA
write_all:
	lds	temp,ucsr1a		;load TransferStatus
	sbrs	temp,udre1		;wait for
	rjmp	write_all		;transfer done
	sts	udr1,data		;send SPI on TXD1 pin
	ret                     ;return

I use USART in SPI mode but that should be a minor difference.
What I notice is that you load SPDR >>before<< testing if SPI is ready to send another byte. You need to check before you load data to SPDR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Switched the order of checking and sending over SPI (again with a waitloop, not the is-free-check because it fails) and added various amounts of initial waiting time before starting the init commands. Nothing changed.

Even with ridiculously long waiting times between transfers, nothing actually happened on the display.

Tried your init sequence - no luck. Not even those "dark pixels" you know from other displays when the contrast is set too high, just nothing.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Even if you don't use /SS pin on PORTB it need to be set to output or high input.
Else AVR will switch into Slave mode.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also make sure that SCK not start as low output, else you might false trig LCD's SPI unit to expect something. I only make Reset low output in init of ports.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found another thing that didn't fix it: I wasn't using the CS pin of the display. Now using it with no change. I attached it to /SS (and made that one an output in the process).

The datasheet says a high CS signal resets counters etc. - so this *should* fix it all. Should...

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tried something new: deactivate SPI and do it all by hand.

Idea is this one: take the byte to send, LSL it, output the carry bit and do a high-low-cycle of the clock to make the display eat it. Difference between "cmd" and "data" versions is only the "A0" bit.

The (very un-optimized) code I used for macros:

.MACRO wait1
	NOP
	NOP
	NOP
	NOP
.ENDMACRO

.MACRO disp_send_cmd_bit
	LSL acc // shift left
	IN acc2, SREG // get SREG
	ANDI acc2, 0b00000001 // get C bit
	LSL acc2 // shift left 3x to the SI position
	LSL acc2
	LSL acc2
	LDI accI, 0b00000001
	OR accI, acc2
	OUT PORTB, acc
	wait1
	SBR accI, (1<<5) // pull clock high
	OUT PORTB, acc
	wait1
	CBR accI, (1<<5) // pull clock low
	OUT PORTB, acc
.ENDMACRO

.MACRO disp_send_cmd_byte
	LDI accI, 0b00000001
	OUT PORTB, accI
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	disp_send_cmd_bit
	LDI accI, 0b00100001
	OUT PORTB, accI
.ENDMACRO

.MACRO disp_send_data_bit
	LSL acc // shift left
	IN acc2, SREG // get SREG
	ANDI acc2, 0b00000001 // get C bit
	LSL acc2 // shift left 3x to the SI position
	LSL acc2
	LSL acc2
	LDI accI, 0b00000011
	OR accI, acc2
	OUT PORTB, acc
	wait1
	SBR accI, (1<<5) // pull clock high
	OUT PORTB, acc
	wait1
	CBR accI, (1<<5) // pull clock low
	OUT PORTB, acc
.ENDMACRO

.MACRO disp_send_data_byte
	LDI accI, 0b00000011
	OUT PORTB, accI
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	disp_send_data_bit
	LDI accI, 0b00100011
	OUT PORTB, accI
.ENDMACRO

and for the code actually doing something:

// PORTB: x x SCL x SI !CS A0 !RS // A0=0:cmd, A0=1:data
LDI acc, 0b00100101 // init
OUT PORTB, acc
LDI acc, 0b00100100 // do reset
OUT PORTB, acc
LDI acc, 0b00100001 // chip select, un-reset
OUT PORTB, acc

LDI acc, 0x40 // Display start line 0
disp_send_cmd_byte
LDI acc, 0xa1 // ADC reverse
disp_send_cmd_byte
LDI acc, 0xc0 // normal com0-com31
disp_send_cmd_byte
LDI acc, 0xa6 // display normal
disp_send_cmd_byte
LDI acc, 0xa2 // set bias 1/9
disp_send_cmd_byte
LDI acc, 0x2f // booster, regulator, follower on
disp_send_cmd_byte
LDI acc, 0xf8 // set internal booster to 3x/4x
disp_send_cmd_byte
LDI acc, 0x00 // 
disp_send_cmd_byte
LDI acc, 0x23 // set contrast
disp_send_cmd_byte
LDI acc, 0x81 // 
disp_send_cmd_byte
LDI acc, 0x1f // 
disp_send_cmd_byte
LDI acc, 0xac // no indicator
disp_send_cmd_byte
LDI acc, 0x00 // 
disp_send_cmd_byte
LDI acc, 0xaf // display on
disp_send_cmd_byte

LDI acc, 80 // "P"
disp_send_data_byte

acc = R16
acc2 = R17
accI = R18

Guess what? Still nothing on the display. There must be *some* way of making the display show something. Anything. I mean there obviously are people who got it working. It's still being sold, so chances are good it *can* be working somehow...

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a similar project on-line:
http://code.google.com/p/dogm128/wiki/dogm132_atmega88_hardware

Concerning your first question, I try to put up a list of important issues with the dogm132:
- Chip Select of the dogm132 must be controlled by the ATMEGA.
- After reset, do some delay before sending something to the DOGM132
- Add a reset circuit to the DOGM132 (see link above)
- Make a high low transition on the chip select line before sending any bytes
- ISP Programmer: Add a pullup on the chip select line
- ATMEGA SPI: SS must be set to output (it might be used as the chip select output)
- ATMEGA SPI: Read data register after sending (this, i guess, was missing in your initial code)

Oliver

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I observed another difference: I set CPOL and CPHA to 0.
See line 258 here:
http://code.google.com/p/dogm128/source/browse/libraries/Dogm/utility/dogmspi.c

Oliver

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi again!

Oliver, I changed the project to (hopefully) match your tips and still, it doesn't work. Where "doesn't work" in this case means it doesn't even run all the way through. I seem to get an endless loop in the SPI "wait for last transmission to complete" in the spi_send procedure. And I don't know why.

For waiting, I used loops here. The µC runs at 8 MHz. Here the currently used code. The obvious include for Register names and the interrupt vectors (just the reset one used to jump to the beginning of the following code) are missing here.

// registers and names
.DEF acc = R16 // accumulator 1
.DEF acc2 = R17 // accumulator 2
.EQU disp_port_w = PORTB
.EQU disp_port_r = PINB
.EQU disp_pin_cs = 2
.EQU disp_pin_a0 = 1
.EQU disp_pin_rs = 0

// prepare stack
LDI acc, high(RAMEND)
OUT SPH, acc
LDI acc, low(RAMEND)
OUT SPL, acc

// init PORTB
LDI acc, 0b00101111 // xtal,xtal,SCL,miso,SI,CS,A0,RS
OUT DDRB, acc
LDI acc, 0b00000000 // clear outputs, disable all pullups
OUT PORTB, acc

// prepare SPI
LDI acc, 0b11010000 // SPI master, prescaler 4
OUT SPCR, acc
LDI acc, 0b00000000 // no 2x speed
OUT SPSR, acc

// enable interrupts globally
SEI

// init the display
RCALL disp_init

// send a character to the display
LDI acc, 80
RCALL disp_sendchar	

// main loop
mainloop:
RJMP mainloop



// PROCEDURE for sending a byte over SPI
spi_send:
// wait for last transmission to complete
spi_send_wait:
IN acc, SPSR
SBRS acc, SPIF
RJMP spi_send_wait
	
// set CS bit
IN acc2, disp_port_r
SBR acc2, (1<<disp_pin_cs)
OUT disp_port_w, acc2
	
// clear CS bit
IN acc2, disp_port_r
CBR acc2, (1<<disp_pin_cs)
OUT disp_port_w, acc2
	
// send data over SPI
OUT SPDR, acc
IN acc, SPDR
	
RET



// PROCEDURE for sending a character
disp_sendchar:
IN acc2, disp_port_r
ORI acc2, (1<<disp_pin_a0)
OUT disp_port_w, acc2
RCALL spi_send
RET



// PROCEDURE for initializing the display
disp_init:
// first of all, wait!
LDI acc, 255
LDI acc2, 255
LDI accI, 3
disp_init_waitloop:
DEC acc
CPI acc, 0
BRNE disp_init_waitloop
DEC acc2
CPI acc2, 0
BRNE disp_init_waitloop
DEC accI
CPI accI, 0
BRNE disp_init_waitloop
	
// clear a0, clear rs
IN acc, disp_port_r
ANDI acc, 0xff&(0<<disp_pin_a0)&(0<<disp_pin_rs)
OUT disp_port_w, acc
	
LDI acc2, 255
disp_init_wait1:
DEC acc2
CPI acc2, 0
BRNE disp_init_wait1

// set rs, clear CS
IN acc, disp_port_r
ORI acc, 1<<disp_pin_rs
OUT disp_port_w, acc
	
LDI acc2, 255
disp_init_wait2:
DEC acc2
CPI acc2, 0
BRNE disp_init_wait2

// display start line set
LDI acc, 0b01000000
RCALL spi_send
	
// ADC select
LDI acc, 0b10100000
RCALL spi_send
	
// Common output mode select
LDI acc, 0b11001000
RCALL spi_send
	
// Display normal/reverse
LDI acc, 0b10100110
RCALL spi_send
	
// LCD bias set: 1/9
LDI acc, 0b10100010
RCALL spi_send
	
// Power control set: booster, regulator and follower on
LDI acc, 0b00101111
RCALL spi_send
	
// Booster ratio set: 3x/4x
LDI acc, 0b11111000
RCALL spi_send
LDI acc, 0b00000000
RCALL spi_send
	
// Contrast set
// V0 voltage
LDI acc, 0b00100011
RCALL spi_send
// Electronic volume mode
LDI acc, 0b10000001
RCALL spi_send
LDI acc, 0b00011111
RCALL spi_send
	
// static indicator set
LDI acc, 0b10101100
RCALL spi_send
LDI acc, 0b00000000
RCALL spi_send
	
// display on
LDI acc, 0b10101111
RCALL spi_send
	
RET

The connections of the display I used (checked on the breadboard):

V0 = 1µF to GND
V1 =  1µF to GND
V2 =  1µF to GND
V3 =  1µF to GND
V4 =  1µF to GND
VSS = GND
CAP2N = 1µF to CAP2P
CAP2P = see above
CAP1P = 1µF to CAP1N
CAP1N = see above
CAP3P = 1µF to CAP1N
VOUT = 1µF to GND
VSS = GND
VDD2 = 3.3V
VDD = 3.3V
SI = AVR MOSI
SCL = AVR SCK
A0 = AVR PB1
RST = AVR PB0 (+10k Pullup to 3.3V)
CS1B = AVR SS/PB2 (+10k Pullup to 3.3V)

I bet it's something really stupid and I should see it right away, that thing keeping the display from working properly.

Any help greatly appreciated!

Markus

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You seem to have your CS operation back to front. Also here

LDI acc, 0b00000000 // clear outputs, disable all pullups 

You should start with CS high.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

The following outline of the code works for my project:

init:
  set CS = 1

send_byte:
  write byte into data register
  wait as long as SPIF flag is 0
  read byte from data register (to clear SPIF flag)

setup_seq:
  set CS = 0
  send several bytes
  set CS = 1

Also, for sending data to the display, it is usually required to set the position where to write the data on the display.

What do you see at the output of the pins? Is there a clock signal and some data?

Oliver

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You should start with CS high.

Following up on JS post and my earlier post regarding init of port pins.

When AVR comes out of reset DDRx and PORTx are all zero. Sort of Hi-Z state where either hi or low can be the result of reading the pin.
Having external pull-up resistors on CS and SCK will put those pins to a known state.

When you then init the port pins you start with changing DDRB. Thereby making CS and SCK low outputs.
Like I said before this might lead to LCD falsely detecting start of an SPI transfer.
This can make the rest of your init of LCD registers to fail.

To avoid this, start by changing PORTB register so that any pins that should end up as high outputs first are set to inputs with pull-up.
THEN you change DDRB register and set the needed pins to outputs. Setting PORTB and DDRB in this order will avoid false triggering of SPI lines.
IIRC once enabling SPI this will override settings of SCK, MOSI and MISO. /SS pin is not overridden and must be manually controlled by the user.
But before init of SPI the pins are passing states that might lead to what I've described above.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot for all the input - with that and some more debugging in the simulator and on hardware (by leds lighting up - or not), I now have at least *something* on the display. Random pixels. I don't know why, but now I know it's not broken and it seems to be working!

What I changed (I hope I don't forget anything):
1) change the PORTB and DDRB setting order
2) start with CS high right after AVR reset (first I thought you mean the *display* reset)
3) keep CS low for the whole init sequence, pull it high immediately afterwards
4) again swapping "wait for SPI ready" and "send byte" commands / structures
5) disable the SPI interrupt for it caused an endless loop in "spi_send:"

When I either get it completely working or get stuck again, I'll post it here. Hopefully, this thread will end with a fully-working step-by-step guide how to talk to a DOGM132x-5 (including common pitfalls) as there doesn't seem to be an easy and working guide anywhere out there. At least I didn't find one that actually worked for me.

Markus

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Always a good step forward to get something displayed on the screen.

Quote:
4) again swapping "wait for SPI ready" and "send byte" commands / structures
If you think harder you should realize that if you wait for SPI ready directly after sending the byte you will be stuck in that loop for some time, instead of using that time to do something else that needs to be done and probably only check SPI ready once when you return to do another SPI transfer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Err... now, I first send, then directly wait (what you would *not* recommend) for SPI send to complete, then read the byte to clear the flag and continue with normal code. This way around it's working. Kind of ill-logic, but working.

Re-reading my past and current code, the endless loop came from the enabled SPI interrupt and the clearing the Interrupt Flag in the wrong position.

During fine-tuning later-on I'll give re-enabling the SPI ready interrupt and handling it with an ISR a try. Or waiting *before* sending - the definitely more sensible approach. But first of all, I'll have to get some pixels onto the display where I want them to be. (which is what I'm currently doing)

Markus

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Markus did you get the point that Oliver made above about SPI operation? That's pretty much a template of SPI operation for most SPI devices.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@John: yes I did - and now (with SPI interrupt switched off) it works.

I can now send characters defined column-by-column in (ATmega-internal) flash memory to the display and have them displayed on the line and position I want them to be.

Still working on the procedures to make it all easy - like give the procedure the flash start address of a string and have the string written to the LCD. Did this before for another display though - so it's not difficult, just time-consuming.

As I have something a little more optimized in ready-to-use chunks, I'll post it here for other people looking for a working solution to start with.

Markus