von
Manni (Gast)
21.05.2019 18:40
Hallo U8G2 Anwender ;)
ich komme leider irgendwie mit der Doku dieser ansonsten mega
hilfreichen Bibliothek U8G2 nicht weiter.
Ich habe hier ein Electronic Assembly OLEDL128-6 Display mit SSD1309
Controller. Dazu habe ich mir ausßerdem die aktuellste Version der U8G2
Bibliothek heruntergeladen und versuche nun, "die tollsten Sachen" damit
zu machen ;)
An und für sich komme ich damit gut zurecht und ich kann das Display im
Software-SPI Modus mit meinem Atmega2560 prima ansteuern.
1 #define F_CPU 16000000UL
2
3 #include <avr/io.h>
4 #include <util/delay.h>
5 #include <stdio.h>
6 #include <u8g2.h>
7
8 #define DISPLAY_CLK_DIR DDRK
9 #define DISPLAY_CLK_PORT PORTK
10 #define DISPLAY_CLK_PIN PK0
11
12 #define DISPLAY_DATA_DIR DDRK
13 #define DISPLAY_DATA_PORT PORTK
14 #define DISPLAY_DATA_PIN PK1
15
16 #define DISPLAY_CS_DIR DDRK
17 #define DISPLAY_CS_PORT PORTK
18 #define DISPLAY_CS_PIN PK3
19
20 #define DISPLAY_DC_DIR DDRK
21 #define DISPLAY_DC_PORT PORTK
22 #define DISPLAY_DC_PIN PK4
23
24 #define DISPLAY_RESET_DIR DDRK
25 #define DISPLAY_RESET_PORT PORTK
26 #define DISPLAY_RESET_PIN PK2
27
28 u8g2_t u8g2;
29
30 uint8_t u8x8_avr_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
31 {
32 uint8_t cycles;
33
34 switch(msg)
35 {
36 case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
37 // At 20Mhz, each cycle is 50ns, the call itself is slower.
38 break;
39 case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
40 // Approximate best case values...
41 #define CALL_CYCLES 26UL
42 #define CALC_CYCLES 4UL
43 #define RETURN_CYCLES 4UL
44 #define CYCLES_PER_LOOP 4UL
45
46 cycles = (100UL * arg_int) / (P_CPU_NS * CYCLES_PER_LOOP);
47
48 if(cycles > CALL_CYCLES + RETURN_CYCLES + CALC_CYCLES)
49 break;
50
51 __asm__ __volatile__ (
52 "1: sbiw %0,1" "\n\t" // 2 cycles
53 "brne 1b" : "=w" (cycles) : "0" (cycles) // 2 cycles
54 );
55 break;
56 case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
57 for(int i=0 ; i < arg_int ; i++)
58 _delay_us(10);
59 break;
60 case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
61 for(int i=0 ; i < arg_int ; i++)
62 _delay_ms(1);
63 break;
64 default:
65 return 0;
66 }
67 return 1;
68 }
69
70 uint8_t u8x8_avr_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
71 {
72 // Re-use library for delays
73
74 switch(msg)
75 {
76 case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
77 DISPLAY_CLK_DIR |= 1<<DISPLAY_CLK_PIN;
78 DISPLAY_DATA_DIR |= 1<<DISPLAY_DATA_PIN;
79 DISPLAY_CS_DIR |= 1<<DISPLAY_CS_PIN;
80 DISPLAY_DC_DIR |= 1<<DISPLAY_DC_PIN;
81 DISPLAY_RESET_DIR |= 1<<DISPLAY_RESET_PIN;
82 break; // can be used to setup pins
83 case U8X8_MSG_GPIO_SPI_CLOCK: // Clock pin: Output level in arg_int
84 if(arg_int)
85 DISPLAY_CLK_PORT |= (1<<DISPLAY_CLK_PIN);
86 else
87 DISPLAY_CLK_PORT &= ~(1<<DISPLAY_CLK_PIN);
88 break;
89 case U8X8_MSG_GPIO_SPI_DATA: // MOSI pin: Output level in arg_int
90 if(arg_int)
91 DISPLAY_DATA_PORT |= (1<<DISPLAY_DATA_PIN);
92 else
93 DISPLAY_DATA_PORT &= ~(1<<DISPLAY_DATA_PIN);
94 break;
95 case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
96 if(arg_int)
97 DISPLAY_CS_PORT |= (1<<DISPLAY_CS_PIN);
98 else
99 DISPLAY_CS_PORT &= ~(1<<DISPLAY_CS_PIN);
100 break;
101 case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
102 if(arg_int)
103 DISPLAY_DC_PORT |= (1<<DISPLAY_DC_PIN);
104 else
105 DISPLAY_DC_PORT &= ~(1<<DISPLAY_DC_PIN);
106 break;
107
108 case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
109 if(arg_int)
110 DISPLAY_RESET_PORT |= (1<<DISPLAY_RESET_PIN);
111 else
112 DISPLAY_RESET_PORT &= ~(1<<DISPLAY_RESET_PIN);
113 break;
114 default:
115 if (u8x8_avr_delay(u8x8, msg, arg_int, arg_ptr)) // check for any delay msgs
116 return 1;
117 u8x8_SetGPIOResult(u8x8, 1); // default return value
118 break;
119 }
120 return 1;
121 }
122
123
124
125 void main(void) {
126
127 u8g2_Setup_ssd1309_128x64_noname0_f(&u8g2, U8G2_R2, u8x8_byte_4wire_sw_spi, u8x8_avr_gpio_and_delay);
128 u8g2_InitDisplay(&u8g2);
129 u8g2_SetPowerSave(&u8g2, 0);
130 u8g2_SetContrast(&u8g2, 128);
131
132 u8g2_ClearBuffer(&u8g2);
133 u8g2_SetFont(&u8g2, u8g2_font_5x7_tf);
134 u8g2_DrawStr(&u8g2, 121, 59, "Hallo Welt!");
135 u8g2_SendBuffer(&u8g2);
136
137 while(1) {
138 }
139
140 }
Soweit, so minimal.
Das Display wird somit im 4-wire Software-SPI Modus betrieben.
Nun würde ich das aber gerne mit dem Hardware-SPI des Atmega2560
betreiben.
In der U8G2 Doku findet man C++/Arduino Beispiele, in denen das gemacht
wird.
Aber im C-Teil der Doku finde dahingehend nix. Heisst das jetzt, das man
Hardware-SPI nur in der Arduino Umgebung konfigurieren und nutzen kann?
In der oben gezeigten Konfiguration ist das Display wirklich
fürchterlich langsam. Meine Hoffnung war, dass es mit Hardware-SPI
schneller läuft.
Kann mir hier jemand auf die Sprünge helfen?
Hat jemand schonmal die U8G2 lib mit einem SSD1309 Controller verwendet?
Vielen Dank vorab ;)
LG, Manni
Hallo,
da ich nun vor dem gleichen "Problem" stehe ... haste was rausbekommen ?
Ich verwend zwar einen ST7920 aber das Prinzip sollt das gleiche sein.
Man übergibt bei der Initialisierung einen Callback für die
SPI-Kommunikation.
Die Init sieht in meinem Fall so aus: 1 u8g2_Setup_st7920_s_128x64_f ( & u8g2 , U8G2_R0 , u8x8_byte_hw_spi , u8x8_gpio_and_delay );
Und der SPI-Callback hat folgende Signatur: 1 uint8_t u8x8_byte_hw_spi ( u8x8_t * u8x8 , uint8_t msg , uint8_t arg_int , void * arg_ptr );
Das hat bei mir eigentlich out-of-the-box funktioniert.
Danke für den Hinweis - habs dann nach der Anleitung in der Doku
hinbekommen.
Ich betreibe hier nenn ATSAM3SD8B mit der ASF 3.39.0 und dem AS7.
Für die dies interessiert hier nenn bissl code: 1 #define SPI_CHIP_SEL 0
2 #define SPI_CLK_POLARITY 1
3 #define SPI_CLK_PHASE 0
4 #define SPI_DLYBS 0x01
5 #define SPI_DLYBCT 0x01
6 #define SPI_BAUDRATE 24000000
7
8 void OLED_SPI_Init (){
9 volatile uint32_t temp ;
10 temp = sysclk_get_cpu_hz () ;
11 UNUSED ( temp );
12
13 spi_enable_clock ( SPI_MASTER_BASE );
14 spi_disable ( SPI_MASTER_BASE );
15 spi_reset ( SPI_MASTER_BASE );
16 spi_set_master_mode ( SPI_MASTER_BASE );
17 spi_set_clock_polarity ( SPI_MASTER_BASE , SPI_CHIP_SEL , SPI_CLK_POLARITY );
18 spi_set_clock_phase ( SPI_MASTER_BASE , SPI_CHIP_SEL , SPI_CLK_PHASE );
19 spi_set_bits_per_transfer ( SPI_MASTER_BASE , SPI_CHIP_SEL , SPI_CSR_BITS_8_BIT );
20 spi_set_baudrate_div ( SPI_MASTER_BASE , SPI_CHIP_SEL , ( sysclk_get_peripheral_hz () / SPI_BAUDRATE ));
21 spi_set_transfer_delay ( SPI_MASTER_BASE , SPI_CHIP_SEL , SPI_DLYBS , SPI_DLYBCT );
22 spi_enable ( SPI_MASTER_BASE );
23 }
24
25 void OLED_SPI_Write ( uint8_t value ){
26 spi_write ( SPI_MASTER_BASE , value , 0 , 0 );
27 while (( spi_read_status ( SPI ) & SPI_SR_TXEMPTY ) == 0 );
28 }
Dann die Anpassungen der U8G2 Callbacks: 1 uint8_t u8x8_arm_delay ( u8x8_t * u8x8 , uint8_t msg , uint8_t arg_int , void * arg_ptr ){
2 switch ( msg ) {
3 case U8X8_MSG_DELAY_NANO :
4 Nop ();
5 break ;
6
7 case U8X8_MSG_DELAY_100NANO :
8 Nop (); // #tbd
9 break ;
10
11 case U8X8_MSG_DELAY_10MICRO :
12 delay_us ( arg_int * 10 );
13 break ;
14
15 case U8X8_MSG_DELAY_MILLI :
16 delay_ms ( arg_int );
17 break ;
18
19 default:
20 return 0 ;
21 }
22 return 1 ;
23 }
24 uint8_t u8x8_arm_gpio_and_delay ( u8x8_t * u8x8 , uint8_t msg , uint8_t arg_int , void * arg_ptr ){
25 switch ( msg ) {
26 case U8X8_MSG_GPIO_AND_DELAY_INIT :
27 break ;
28
29 case U8X8_MSG_GPIO_SPI_CLOCK :
30 break ;
31
32 case U8X8_MSG_GPIO_SPI_DATA :
33 break ;
34
35 case U8X8_MSG_GPIO_CS :
36 ioport_set_pin_level ( SPI_OLED_CS_GPIO , arg_int );
37 break ;
38
39 case U8X8_MSG_GPIO_DC :
40 ioport_set_pin_level ( OLED_DC_GPIO , arg_int );
41 break ;
42
43 case U8X8_MSG_GPIO_RESET :
44 ioport_set_pin_level ( OLED_RST_GPIO , arg_int );
45 break ;
46
47 default:
48 if ( u8x8_arm_delay ( u8x8 , msg , arg_int , arg_ptr ))
49 return 1 ;
50 u8x8_SetGPIOResult ( u8x8 , 1 ); // default return value
51 break ;
52 }
53 return 1 ;
54 }
55 uint8_t u8x8_byte_arm_hw_spi ( u8x8_t * u8x8 , uint8_t msg , uint8_t arg_int , void * arg_ptr ) {
56 uint8_t * data ;
57
58 switch ( msg ) {
59 case U8X8_MSG_BYTE_SEND :
60 data = ( uint8_t * ) arg_ptr ;
61 while ( arg_int > 0 ) {
62 OLED_SPI_Write (( uint8_t ) * data );
63 data ++ ;
64 arg_int -- ;
65 }
66 break ;
67
68 case U8X8_MSG_BYTE_INIT :
69 OLED_SPI_Init ();
70 u8x8_gpio_SetCS ( u8x8 , u8x8 -> display_info -> chip_disable_level );
71 break ;
72
73 case U8X8_MSG_BYTE_SET_DC :
74 u8x8_gpio_SetDC ( u8x8 , arg_int );
75 break ;
76
77 case U8X8_MSG_BYTE_START_TRANSFER :
78 u8x8_gpio_SetCS ( u8x8 , u8x8 -> display_info -> chip_enable_level );
79 u8x8 -> gpio_and_delay_cb ( u8x8 , U8X8_MSG_DELAY_NANO , u8x8 -> display_info -> post_chip_enable_wait_ns , NULL );
80 break ;
81
82 case U8X8_MSG_BYTE_END_TRANSFER :
83 u8x8 -> gpio_and_delay_cb ( u8x8 , U8X8_MSG_DELAY_NANO , u8x8 -> display_info -> pre_chip_disable_wait_ns , NULL );
84 u8x8_gpio_SetCS ( u8x8 , u8x8 -> display_info -> chip_disable_level );
85 break ;
86
87 default:
88 return 0 ;
89 }
90 return 1 ;
91 }
Dann mal zu Testzwecken was ausgeben : 1 #include <USER.h>
2
3 BOARD_STATUS vBoard_Status ;
4
5 void BOARD_Init (){
6 board_init ();
7
8 ...
9
10 MEMORY_Init ();
11 GENERIC_USART_Init ();
12 CMDHANDLER_Init ();
13
14 ...
15
16
17 BOARD_Start ();
18 }
19
20 void BOARD_Start (){
21 u8g2_Setup_ssd1309_128x64_noname0_f ( & u8g2 , U8G2_R0 , u8x8_byte_arm_hw_spi , u8x8_arm_gpio_and_delay );
22 u8g2_InitDisplay ( & u8g2 );
23 u8g2_SetPowerSave ( & u8g2 , 0 );
24 u8g2_SetDisplayRotation ( & u8g2 , U8G2_R2 );
25
26 u8g2_ClearBuffer ( & u8g2 );
27 u8g2_ClearDisplay ( & u8g2 );
28 u8g2_SetFont ( & u8g2 , u8g2_font_ncenB08_tf );
29
30 u8g2_DrawStr ( & u8g2 , 1 , 10 , "Demo Text" );
31 u8g2_UpdateDisplay ( & u8g2 );
32
33 while ( 1 ){
34 u8g2_ClearBuffer ( & u8g2 );
35 u8g2_DrawStr ( & u8g2 , 1 , 10 , "Demo Text" );
36
37 for ( int i = 0 ; i < 40 ; i ++ ) {
38 u8g2_DrawFrame ( & u8g2 , 10 , 20 , i * 2 , 10 );
39 u8g2_DrawFrame ( & u8g2 , 10 , 50 , 80 - ( i * 2 ), 10 );
40 u8g2_UpdateDisplay ( & u8g2 );
41 }
42 }
43 }
44 void BOARD_ProcessIO (){
45 ...
46 }
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.