NHD-0216CW module using SPI - Question
Hi,
I will be using this module to display the frequency and signal strength for a receiver I am building. The device controlling all functions of the receiver is an Atmel XMEGA256A3BU Xplained board. SPI is working fine on this board and currently controls two digital synthesizers and a relay board to select 1 of 15 band pass filters.
I read in the module documentation that this module uses the US2066 display controller. I downloaded the document for the US2066 controller and now understand the format of the data/commands to be sent to the display. The command descriptions in section 7 and the three command tables in section 6 indicate that three signals (IS, RE, SD) need to be set for the controller to correctly identify which command the user wishes to execute. I could not locate data in the documentation that references how to set these three signals.
Any code snips to initialize the display module would be very helpful, as well.
Thanks in advance for any assistance.
Regards,
Fred
-
Morning Fred,
Below is some example code written for the Arduino
https://github.com/NewhavenDisplay/NHD_US2066
Next, (IS, RE and SD) will need to be configured correctly in order for the controller to correctly identify which command the user wishes to execute. Take a look at the initialization sequence (File: NHD_US2066.cpp). The code is heavily commented and should clear up any questions.
Please keep us posted on your progress!0 -
Hi Paul,
Thanks for the assistance. Unfortunately, no joy yet. The code I wrote is below. I did change a few of the commands, as I have a 2x16 display, and the code on the US2066 directory I think is for a 4-line display. Also, I am using 5V digital logic, so I changed that command. I think all else is the same. The SPI is definitely sending least significant bit first, and the /CS line is going low before the data is transmitted. I am using a board with 2n7000-based level shifters for clock, SDI, and /CS. /RES is tied to +5V.
I also tried the initialization code at a much lower baud rate, without success.
The following pins are tied to +5V:
2,3,16
The following lines are tied to 0V:
1,4,5,6,10,11,12,13,14,17,18,19,20
The following pins are connected to the SPI port on the Atmel processor, first passing through a level-shifter board
7 - SPI clock
8 - SPI data out from
9 - Floating
15 - /CS
Code follows:display_command:
push temp ; save command
cbi VPORT2_OUT, oled_enable ; clear the bit so the display will listen
ldi temp, $1f ; LSB transmits first, so reverse command preamble byte
rcall sout ; output the command preamble
pop temp ; retrieve command
mov r17, temp ; save a copy
; command byte needs to be transmitted as
; D0 D1 D2 D3 0 0 0 0
; D4 D5 D6 D7 0 0 0 0
; the SPI UART is already configured to transmit
; LSB first, so all we need to do is to mask off
; the D0-D3, transmit, then shift left D4-D7 to
; D0-D3 and transmit.
andi temp, $0F
rcall sout
mov temp, r17 ; get the original byte back
swap temp ; swap nibbles
andi temp, $0F
rcall sout
sbi VPORT2_OUT, oled_enable ; set bit so display will go deaf
ret
display_data:
push temp ; save data
cbi VPORT2_OUT, oled_enable ; clear the bit so the display will listen
ldi temp, $5f ; LSB transmits first, so reverse data preamble byte
rcall sout ; output the command preamble
pop temp ; retrieve data
mov r17, temp ; save a copy
; data byte needs to be transmitted as
; D0 D1 D2 D3 0 0 0 0
; D4 D5 D6 D7 0 0 0 0
; the SPI UART is already configured to transmit
; LSB first, so all we need to do is to mask off
; the D0-D3, transmit, then shirt left D4-D7 to
; D0-D3 and transmit.
andi temp, $0F
rcall sout
mov temp, r17 ; get the original byte back
swap temp
andi temp, $0F
rcall sout
sbi VPORT2_OUT, oled_enable ; set bit so display will go deaf
ret
init_display:
ldi temp, $2A ; //function set (extended command set)
rcall display_command
ldi temp, $71; //function selection A
rcall display_command
ldi temp, $5c; // (0x5C) = enable regulator (5V I/O)
rcall display_data
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $08; //display off, cursor off, blink off
rcall display_command
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $D5; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $70; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $08; //extended function set (2-lines)
rcall display_command
ldi temp, $06; //COM SEG direction
rcall display_command
ldi temp, $72; //function selection B
rcall display_command
ldi temp, $00; //ROM CGRAM selection
rcall display_data
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $DA; //set SEG pins hardware configuration
rcall display_command
ldi temp, $10; //set SEG pins hardware configuration
rcall display_command
ldi temp, $DC; //function selection C
rcall display_command
ldi temp, $10; //function selection C
rcall display_command
ldi temp, $81; //set contrast control
rcall display_command
ldi temp, $7F; //set contrast control
rcall display_command
ldi temp, $D9; //set phase length
rcall display_command
ldi temp, $F1; //set phase length
rcall display_command
ldi temp, $DB; //set VCOMH deselect level
rcall display_command
ldi temp, $40; //set VCOMH deselect level
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $01; //clear display
rcall display_command
ldi temp, $80; // SET dram ADDRESS TO 0X00
rcall display_command
ldi temp, $0F; //display ON
rcall display_command
ldi temp, $01
rcall display_command
ldi temp, $45
rcall display_data
ret
;Would you please check the initialization code and let me know if this looks OK? Again, your assistance is greatly appreciated. This is the last build step for my new receiver.
Regards,
Fred« Last Edit: June 25, 2015, 10:13:44 AM by atlantaswl »0 -
Hi Paul,
Thinking there might be an issue using the SPI on the Atmel processor, i rewrote the c code in the example program in AVR assembler, and would love to share the code with the forum, and the display is now working - almost. The issue seems to be now the required delay for the various commands. Do you or someone on the forum have any guidelines on required delays for a few of the commands requiring such? It seems as if a delay will be required if the /RES line is brought low and high, and the display on command seems to require quite a long delay (.1 seconds?)
Thanks all for looking and sharing.
Regards, Fred0 -
Here is the AVR assembler code. The argument (command or data) is loaded into the temp register (r16), and either display_command or display_data is called. VPORT2 is mapped to Port C and VPORT3 is mapped to Port A. For those interested, once a port is mapped to a virtual port, individual bits within a port can be turned on (SBI) or turned off (CBI), without regard to what the other pins on that port are set to.
; registers used:
; R16 will have the command or data byte already set by the caller
; R17 is used to store the initial preamble (command or data)
; R18 is used as a loop counter
display_command:
cbi VPORT2_OUT, oled_enable ; clear bit so display will listen
ldi r17, $f8 ; command preamble
ldi r18, 8 ; times through
dcommand1: cbi VPORT3_OUT, oled_clock ; clock goes low
lsl r17 ; high order bit shifted into Cary Condition status bit
brcc dcommand2 ; if Cary clear, bit is zero, output a zero
sbi VPORT3_OUT, oled_data ; data goes high
rjmp dcommand3
dcommand2: cbi VPORT3_OUT, oled_data ; data goes low
dcommand3: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne dcommand1
; Preamble sent, now to send the command
ldi r18, 4 ; send only 4 bits at a time
dcommand4: cbi VPORT3_OUT, oled_clock ; clock goes low
lsr temp ; LSB goes into CC
brcc dcommand5 ; if Carry bit clear, data bit is a 0
sbi VPORT3_OUT, oled_data ; data goes high
rjmp dcommand6
dcommand5: cbi VPORT3_OUT, oled_data ; data gles low
dcommand6: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne dcommand4
; four bits have gone, need to send four 0's
ldi r18, 4
dcommand7: cbi VPORT3_OUT, oled_clock ; clock goes low
cbi VPORT3_OUT, oled_data ; data goes low
sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne dcommand7
; now handle the upper 4 bits of the command
ldi r18, 4
dcommand8: cbi VPORT3_OUT, oled_clock ; clock goes low
lsr temp
brcc dcommand9
sbi VPORT3_OUT, oled_data ; data goes high
rjmp dcommand10
dcommand9: cbi VPORT3_OUT, oled_data ; data goes low
dcommand10: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne dcommand8
; last four bits have gone, need to send four 0's
ldi r18, 4
dcommand11: cbi VPORT3_OUT, oled_clock ; clock goes low
cbi VPORT3_OUT, oled_data ; data goes low
sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne dcommand11
sbi VPORT2_OUT, oled_enable ; set bit so display will go deaf
ret ; whew, done with the command!!!
display_data: cbi VPORT2_OUT, oled_enable ; clear bit so display will listen
ldi r17, $fa ; command preamble
ldi r18, 8 ; times through
ddata1: cbi VPORT3_OUT, oled_clock ; clock goes low
lsl r17 ; set CC based on highest remaining bit
brcc ddata2 ; bit is zero, output a zero
sbi VPORT3_OUT, oled_data ; data goes high
rjmp ddata3
ddata2: cbi VPORT3_OUT, oled_data ; data goes low
ddata3: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne ddata1
; Preamble sent, now to send the command
ldi r18, 4 ; last 4 nibbles first
ddata4: cbi VPORT3_OUT, oled_clock ; clock goes low
lsr temp ; LSB goes into CC
brcc ddata5 ; if CC clear, data goes low
sbi VPORT3_OUT, oled_data ; data goes high
rjmp ddata6
ddata5: cbi VPORT3_OUT, oled_data ; data goes low
ddata6: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne ddata4
; four bits have gone, need to send four 0's
ldi r18, 4
ddata7: cbi VPORT3_OUT, oled_clock ; clock goes low
cbi VPORT3_OUT, oled_data ; data goes low
sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne ddata7
; now handle the upper 4 bits of the data
ldi r18, 4
ddata8: cbi VPORT3_OUT, oled_clock ; clock goes low
lsr temp
brcc ddata9
sbi VPORT3_OUT, oled_data ; data goes high
rjmp ddata10
ddata9: cbi VPORT3_OUT, oled_data ; data goes low
ddata10: sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne ddata8
; last four bits have gone, need to send four 0's
ldi r18, 4
ddata11: cbi VPORT3_OUT, oled_clock ; clock goes low
cbi VPORT3_OUT, oled_data ; data goes low
sbi VPORT3_OUT, oled_clock ; clock goes high
dec r18
brne ddata11
sbi VPORT2_OUT, oled_enable ; set bit so display will go deaf
rcall display_delay ; 5 ms delay
ret ; whew, done with the data!!!« Last Edit: June 27, 2015, 07:45:40 PM by atlantaswl »0 -
Afternoon Fred,
Thank you for sharing your code :)
Regarding the delay for the /RES line, you will need to follow the sequence below:
Power on
Wait at least 1ms
Bring reset low
Wait at least 3us
Bring reset high
Wait at least 200ms before sending commands
Finally, the .1 second delay listed in the example code was used during mock-up and is in no way the min value. For specific delay times please refer to the US2066 datasheet:
https://newhavendisplay.com/content/app_notes/US2066.pdf
Hope this helps!0 -
Hello Fred,
I am currently in a situation very similar to the one you were in a couple of weeks back. I likewise am working with a screen that has a US2066 driver and am looking to use SPI for communication. The two differences between our setups is that my screen is 2x20 (instead of your 2x16) and I am running it in 'Low Voltage' mode (instead of your 5v mode).
I've cross compared my setup code with yours and have identified two points of deviation. One pertains to 3v versus 5v mode and thus is to be expected. The other difference I couldn't resolve/figure out what you were setting. I've highlighted the one in question below.Quoteinit_display:
ldi temp, $2A ; //function set (extended command set)
rcall display_command
ldi temp, $71; //function selection A
rcall display_command
ldi temp, $5c; // (0x5C) = enable regulator (5V I/O)
rcall display_data
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $08; //display off, cursor off, blink off
rcall display_command
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $D5; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $70; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $08; //extended function set (2-lines)
rcall display_command
ldi temp, $06; //COM SEG direction
rcall display_command
ldi temp, $72; //function selection B
rcall display_command
ldi temp, $00; //ROM CGRAM selection
rcall display_data
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $DA; //set SEG pins hardware configuration
rcall display_command
ldi temp, $10; //set SEG pins hardware configuration
rcall display_command
ldi temp, $DC; //function selection C
rcall display_command
ldi temp, $10; //function selection C
rcall display_command
ldi temp, $81; //set contrast control
rcall display_command
ldi temp, $7F; //set contrast control
rcall display_command
ldi temp, $D9; //set phase length
rcall display_command
ldi temp, $F1; //set phase length
rcall display_command
ldi temp, $DB; //set VCOMH deselect level
rcall display_command
ldi temp, $40; //set VCOMH deselect level
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $01; //clear display
rcall display_command
ldi temp, $80; // SET dram ADDRESS TO 0X00
rcall display_command
ldi temp, $0F; //display ON
rcall display_command
ldi temp, $01
rcall display_command
ldi temp, $45
rcall display_data
ret
;
Looking at the driver datasheet I could not resolve what the commands was (it seemed to deviate from the table). For reference I'm looking at the second line in the row dedicated to the 'command' named 'Function Selection C' on page 32 of the driver's datasheethttps://newhavendisplay.com/content/app_notes/US2066.pdf
I am wondering if you changed this - or any other lines in your initialization - in between your posting it and your getting the OLED screen to work?
Secondly, it sounds as though you ended up placing delays at certain points in your code to help it function. In addition to the delays related to 'reset', did you also decide to place a blanket delay after each command/data byte is sent?
Thank you very much Fred, I greatly appreciate any insight you can provide!0 -
Hi,
I found it expeditious to change the interface to parallel. Uses many more pins, but the display works perfectly now. One thing I will say, is that by verifying the command has completed by reading the BF before sending the next command certainly removed any issues from the display initialization. If I had implemented the logic to check the BF flag in serial mode, I believe I would not have had a problem initializing the display. But, can't be certain, since I did not implement that code in SPI mode. Since I got this working using the 8080 8-bit interface, I will not be revisiting initializing and using this chip using SPI. The controller is the Atmel XMEGA 256A3BU developer kit. Port C (J1) is used for the parallel data, and using SPI on port E (J4) for communication to two DDS modules and a 16 port relay board.
Good luck,
Fred0 -
Thought I share the assembler code using the 8080 8-bit interface.
init_display:
ldi temp, RES
sts PORTA_OUTCLR, temp
rcall display_delay
sts PORTA_OUTSET, temp
ldi temp, $2A ; function set (extended command set)
rcall display_command
ldi temp, $71; //function selection A
rcall display_command
ldi temp, $00; // data($00) = disable internal VDD regulator (2.8V I/O). data(0x5C) = enable regulator (5V I/O)
rcall display_data
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $08; //display off, cursor off, blink off
rcall display_command
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $D5; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $70; //set display clock divide ratio/oscillator frequency
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $08; //extended function set (2-lines)
rcall display_command
ldi temp, $06; //COM SEG direction
rcall display_command
ldi temp, $72; //function selection B
rcall display_command
ldi temp, $00; //ROM CGRAM selection
rcall display_data
ldi temp, $2A; //function set (extended command set)
rcall display_command
ldi temp, $79; //OLED command set enabled
rcall display_command
ldi temp, $DA; //set SEG pins hardware configuration
rcall display_command
ldi temp, $10; //set SEG pins hardware configuration
rcall display_command
ldi temp, $DC; //function selection C
rcall display_command
ldi temp, $00; //function selection C
rcall display_command
ldi temp, $81; //set contrast control
rcall display_command
ldi temp, $08; //set contrast control
rcall display_command
ldi temp, $D9; //set phase length
rcall display_command
ldi temp, $F1; //set phase length
rcall display_command
ldi temp, $DB; //set VCOMH deselect level
rcall display_command
ldi temp, $40; //set VCOMH deselect level
rcall display_command
ldi temp, $78; //OLED command set disabled
rcall display_command
ldi temp, $28; //function set (fundamental command set)
rcall display_command
ldi temp, $01; //clear display
rcall display_command
ldi temp, $80 ; set DDRAM ADDR to 0x00
rcall display_command
ldi temp, $0C; //display ON
rcall display_command
sbi GPIO_GPIOR1, display_ok ; let the world know we are now initialized
ret
display_delay: ; a counter/timer interrupts every 6 ms and increments dlycnt.
clr dlycnt
display_delay1:
cpi dlycnt,1 ; approx 6 ms
brne display_delay1
ret
check_ready: ; We need to ensure the last command has completed
push temp ; save command on stack
ldi temp, DC
sts PORTA_OUTCLR, temp ; This is a command
ldi temp, CS
sts PORTA_OUTCLR, temp ; Select the display
ldi temp, RD
sts PORTA_OUTCLR, temp ; command to read data to get the BUSY_FLAG
lds temp, PORTA_IN ; This is the first (dummy) byte to synchronize the display processor with this one
tst_again: ldi temp, RD
sts PORTA_OUTSET, temp ; bring RD high
sts PORTA_OUTCLR, temp ; bring RD line low to read the busy flag
lds temp, PORTA_IN ; get the data byte
sbrc temp, BUSY
rjmp tst_again
ldi temp, RD
sts PORTA_OUTSET, temp ; reset RD line to high, we are done reading
ldi temp, CS
sts PORTA_OUTSET, temp ; reset CS line to high
pop temp ; restore command, we are done
ret
display_command:
rcall check_ready ; see if we are not busy for the next command
; first check to make sure last command is finished
push temp ; save the command on the stack
ldi temp, DC
sts PORTA_OUTCLR, temp ; Bring D/C line to low for a command byte
ldi temp, CS
sts PORTA_OUTCLR, temp ; Bring /CS line to low
ldi temp, WR
sts PORTA_OUTCLR, temp ; Bring /WR line to low to write
pop temp ; retrieve command from stack
sts PORTC_OUT, temp ; set all 8 bits of PORTC
ldi temp, WR
sts PORTA_OUTSET, temp ; Bring WR line to high
; let DC remain where it is, but end command by resetting /CS
ldi temp, CS
sts PORTA_OUTSET, temp
; we are now done
ret
display_data:
push temp ; save the command on the stack
ldi temp, DC
sts PORTA_OUTSET, temp ; Bring D/C line to high for a data byte
ldi temp, CS
sts PORTA_OUTCLR, temp ; Bring /CS line to low
ldi temp, WR
sts PORTA_OUTCLR, temp ; Bring /WR line to low to write
pop temp ; retrieve command from stack
sts PORTC_OUT, temp ; set all 8 bits of PORTC
ldi temp, WR
sts PORTA_OUTSET, temp ; Bring WR line to high
; let DC remain where it is, but end command by resetting /CS
ldi temp, CS
sts PORTA_OUTSET, temp
; we are now done
ret0 -
Hi Fred,
Thank you for sharing! :)0
Please sign in to leave a comment.
Comments
9 comments