2424 * THE SOFTWARE.
2525 */
2626
27- #include "shared-bindings/paralleldisplay/ParallelBus.h"
28-
2927#include <stdint.h>
28+ #include <string.h>
3029
31- #include "common-hal/microcontroller/Pin .h"
32- #include "py/runtime .h"
30+ #include "shared-bindings/paralleldisplay/ParallelBus .h"
31+ #include "shared-bindings/microcontroller/Pin .h"
3332#include "shared-bindings/digitalio/DigitalInOut.h"
3433#include "shared-bindings/microcontroller/__init__.h"
3534
35+ #include "common-hal/audiobusio/__init__.h"
36+ #include "common-hal/microcontroller/Pin.h"
37+ #include "py/runtime.h"
38+
39+ #include "i2s_lcd_driver.h"
40+ #include "driver/gpio.h"
3641/*
3742 * Current pin limitations for ESP32-S2 ParallelBus:
3843 * - data0 pin must be byte aligned
3944 */
4045
41- void common_hal_paralleldisplay_parallelbus_construct (paralleldisplay_parallelbus_obj_t * self ,
42- const mcu_pin_obj_t * data0 , const mcu_pin_obj_t * command , const mcu_pin_obj_t * chip_select ,
46+ void common_hal_paralleldisplay_parallelbus_construct_nonsequential (paralleldisplay_parallelbus_obj_t * self ,
47+ uint8_t n_pins , mcu_pin_obj_t * * data_pins ,
48+ const mcu_pin_obj_t * command , const mcu_pin_obj_t * chip_select ,
4349 const mcu_pin_obj_t * write , const mcu_pin_obj_t * read , const mcu_pin_obj_t * reset , uint32_t frequency ) {
4450
45- uint8_t data_pin = data0 -> number ;
46- if (data_pin % 8 != 0 ) {
47- mp_raise_ValueError (translate ("Data 0 pin must be byte aligned." ));
51+ if (n_pins != 8 && n_pins != 16 ) {
52+ mp_raise_ValueError_varg (translate ("Number of data_pins must be 8 or 16, not %d" ), n_pins );
4853 }
4954
50- for (uint8_t i = 0 ; i < 8 ; i ++ ) {
51- if (!pin_number_is_free ( data_pin + i )) {
55+ for (uint8_t i = 0 ; i < n_pins ; i ++ ) {
56+ if (!common_hal_mcu_pin_is_free ( data_pins [ i ] )) {
5257 mp_raise_ValueError_varg (translate ("Bus pin %d is already in use" ), i );
5358 }
5459 }
5560
56- gpio_dev_t * g = & GPIO ; // this is the GPIO registers, see "extern gpio_dev_t GPIO" from file:gpio_struct.h
61+ // This will throw if unsuccessful. Everything following is guaranteed to succeed.
62+ port_i2s_allocate_i2s0 ();
5763
58- // Setup the pins as "Simple GPIO outputs" see section 19.3.3 of the ESP32-S2 Reference Manual
59- // Enable pins with "enable_w1ts"
60-
61- for (uint8_t i = 0 ; i < 8 ; i ++ ) {
62- g -> enable_w1ts = (0x1 << (data_pin + i ));
63- g -> func_out_sel_cfg [data_pin + i ].val = 256 ; /* setup output pin for simple GPIO Output, (0x100 = 256) */
64-
65- }
64+ i2s_lcd_config_t config = {
65+ .data_width = n_pins ,
66+ .pin_num_cs = common_hal_mcu_pin_number (chip_select ),
67+ .pin_num_wr = common_hal_mcu_pin_number (write ), // write strobe
68+ .pin_num_rs = common_hal_mcu_pin_number (command ), // The "register select" pin is called "command" by CircuitPython
69+ .clk_freq = frequency ,
70+ .i2s_port = 0 ,
71+ .swap_data = false,
72+ .buffer_size = 512 ,
73+ };
6674
67- /* From my understanding, there is a limitation of the ESP32-S2 that does not allow single-byte writes
68- * into the GPIO registers. See section 10.3.3 regarding "non-aligned writes" into the registers.
69- */
70-
71-
72- if (data_pin < 31 ) {
73- self -> bus = (uint32_t * )& g -> out ; // pointer to GPIO output register (for pins 0-31)
75+ if (reset != NULL ) {
76+ common_hal_never_reset_pin (reset );
77+ self -> reset_pin_number = reset -> number ;
7478 } else {
75- self -> bus = ( uint32_t * ) & g -> out1 . val ; // pointer to GPIO output register (for pins >= 32)
79+ self -> reset_pin_number = NO_PIN ;
7680 }
7781
78- /* SNIP - common setup of command, chip select, write and read pins, same as from SAMD and NRF ports */
79- self -> command .base .type = & digitalio_digitalinout_type ;
80- common_hal_digitalio_digitalinout_construct (& self -> command , command );
81- common_hal_digitalio_digitalinout_switch_to_output (& self -> command , true, DRIVE_MODE_PUSH_PULL );
82-
83- self -> chip_select .base .type = & digitalio_digitalinout_type ;
84- common_hal_digitalio_digitalinout_construct (& self -> chip_select , chip_select );
85- common_hal_digitalio_digitalinout_switch_to_output (& self -> chip_select , true, DRIVE_MODE_PUSH_PULL );
86-
87- self -> write .base .type = & digitalio_digitalinout_type ;
88- common_hal_digitalio_digitalinout_construct (& self -> write , write );
89- common_hal_digitalio_digitalinout_switch_to_output (& self -> write , true, DRIVE_MODE_PUSH_PULL );
90-
91- self -> read .base .type = & digitalio_digitalinout_type ;
92- common_hal_digitalio_digitalinout_construct (& self -> read , read );
93- common_hal_digitalio_digitalinout_switch_to_output (& self -> read , true, DRIVE_MODE_PUSH_PULL );
94-
95- self -> data0_pin = data_pin ;
96-
97- if (write -> number < 32 ) {
98- self -> write_clear_register = (uint32_t * )& g -> out_w1tc ;
99- self -> write_set_register = (uint32_t * )& g -> out_w1ts ;
100- } else {
101- self -> write_clear_register = (uint32_t * )& g -> out1_w1tc .val ;
102- self -> write_set_register = (uint32_t * )& g -> out1_w1ts .val ;
82+ for (uint8_t i = 0 ; i < n_pins ; i ++ ) {
83+ common_hal_never_reset_pin (data_pins [i ]);
84+ config .pin_data_num [i ] = common_hal_mcu_pin_number (data_pins [i ]);
10385 }
10486
105- // Check to see if the data and write pins are on the same register:
106- if ((((self -> data0_pin < 32 ) && (write -> number < 32 ))) ||
107- (((self -> data0_pin > 31 ) && (write -> number > 31 )))) {
108- self -> data_write_same_register = true; // data pins and write pin are on the same register
109- } else {
110- self -> data_write_same_register = false; // data pins and write pins are on different registers
87+ if (read != NULL ) {
88+ common_hal_never_reset_pin (read );
89+ gpio_config_t read_config = {
90+ .pin_bit_mask = 1ull << read -> number ,
91+ .mode = GPIO_MODE_OUTPUT ,
92+ .pull_up_en = GPIO_PULLUP_DISABLE ,
93+ .pull_down_en = GPIO_PULLDOWN_DISABLE ,
94+ .intr_type = GPIO_INTR_DISABLE ,
95+ };
96+ gpio_config (& read_config );
97+ self -> read_pin_number = read -> number ;
98+ gpio_set_level (read -> number , true);
11199 }
112100
101+ common_hal_never_reset_pin (chip_select );
102+ common_hal_never_reset_pin (command );
103+ common_hal_never_reset_pin (read );
104+ common_hal_never_reset_pin (reset );
105+ common_hal_never_reset_pin (write );
113106
114- self -> write_mask = 1 << (write -> number % 32 ); /* the write pin triggers the LCD to latch the data */
107+ self -> config = config ;
108+ self -> handle = i2s_lcd_driver_init (& config );
115109
116- /* SNIP - common setup of the reset pin, same as from SAMD and NRF ports */
117- self -> reset .base .type = & mp_type_NoneType ;
118- if (reset != NULL ) {
119- self -> reset .base .type = & digitalio_digitalinout_type ;
120- common_hal_digitalio_digitalinout_construct (& self -> reset , reset );
121- common_hal_digitalio_digitalinout_switch_to_output (& self -> reset , true, DRIVE_MODE_PUSH_PULL );
122- never_reset_pin_number (reset -> number );
123- common_hal_paralleldisplay_parallelbus_reset (self );
110+ if (!self -> handle ) {
111+ port_i2s_reset_instance (0 );
112+ mp_raise_RuntimeError (translate ("Internal error" ));
124113 }
114+ }
125115
126- never_reset_pin_number (command -> number );
127- never_reset_pin_number (chip_select -> number );
128- never_reset_pin_number (write -> number );
129- never_reset_pin_number (read -> number );
130- for (uint8_t i = 0 ; i < 8 ; i ++ ) {
131- never_reset_pin_number (data_pin + i );
132- }
133116
117+ void common_hal_paralleldisplay_parallelbus_construct (paralleldisplay_parallelbus_obj_t * self ,
118+ const mcu_pin_obj_t * data0 , const mcu_pin_obj_t * command , const mcu_pin_obj_t * chip_select ,
119+ const mcu_pin_obj_t * write , const mcu_pin_obj_t * read , const mcu_pin_obj_t * reset , uint32_t frequency ) {
120+ char buf [7 ];
121+ mcu_pin_obj_t * data_pins [8 ];
122+ for (int i = 0 ; i < 8 ; i ++ ) {
123+ snprintf (buf , sizeof (buf ), "GPIO%d" , data0 -> number + i );
124+ data_pins [i ] = validate_obj_is_free_pin (mp_obj_dict_get (MP_OBJ_FROM_PTR (& mcu_pin_globals ), mp_obj_new_str (buf , strlen (buf ))));
125+ }
126+ common_hal_paralleldisplay_parallelbus_construct_nonsequential (self , 8 , data_pins , command , chip_select , write , read , reset , frequency );
134127}
135128
129+
136130void common_hal_paralleldisplay_parallelbus_deinit (paralleldisplay_parallelbus_obj_t * self ) {
131+ if (!self -> handle ) {
132+ return ;
133+ }
134+ i2s_lcd_driver_deinit (self -> handle );
135+ self -> handle = NULL ;
137136 /* SNIP - same as from SAMD and NRF ports */
138- for (uint8_t i = 0 ; i < 8 ; i ++ ) {
139- reset_pin_number (self -> data0_pin + i );
137+ for (uint8_t i = 0 ; i < self -> config . data_width ; i ++ ) {
138+ reset_pin_number (self -> config . pin_data_num [ i ] );
140139 }
141140
142- reset_pin_number (self -> command .pin -> number );
143- reset_pin_number (self -> chip_select .pin -> number );
144- reset_pin_number (self -> write .pin -> number );
145- reset_pin_number (self -> read .pin -> number );
146- reset_pin_number (self -> reset .pin -> number );
141+ reset_pin_number (self -> config .pin_num_cs );
142+ reset_pin_number (self -> config .pin_num_wr );
143+ reset_pin_number (self -> read_pin_number );
144+ reset_pin_number (self -> config .pin_num_rs );
145+ reset_pin_number (self -> reset_pin_number );
146+
147+ port_i2s_reset_instance (0 );
147148}
148149
149150bool common_hal_paralleldisplay_parallelbus_reset (mp_obj_t obj ) {
150151 /* SNIP - same as from SAMD and NRF ports */
151152 paralleldisplay_parallelbus_obj_t * self = MP_OBJ_TO_PTR (obj );
152- if (self -> reset . base . type == & mp_type_NoneType ) {
153+ if (self -> reset_pin_number == NO_PIN ) {
153154 return false;
154155 }
155156
156- common_hal_digitalio_digitalinout_set_value ( & self -> reset , false);
157+ gpio_set_level ( self -> reset_pin_number , false);
157158 common_hal_mcu_delay_us (4 );
158- common_hal_digitalio_digitalinout_set_value ( & self -> reset , true);
159+ gpio_set_level ( self -> reset_pin_number , true);
159160 return true;
160161
161162}
@@ -166,62 +167,25 @@ bool common_hal_paralleldisplay_parallelbus_bus_free(mp_obj_t obj) {
166167}
167168
168169bool common_hal_paralleldisplay_parallelbus_begin_transaction (mp_obj_t obj ) {
169- /* SNIP - same as from SAMD and NRF ports */
170170 paralleldisplay_parallelbus_obj_t * self = MP_OBJ_TO_PTR (obj );
171- common_hal_digitalio_digitalinout_set_value (& self -> chip_select , false);
172- return true;
171+ bool r = i2s_lcd_acquire_nonblocking (self -> handle , 1 );
172+ if (r ) {
173+ gpio_set_level (self -> config .pin_num_cs , false);
174+ }
175+ return r ;
173176}
174177
175178void common_hal_paralleldisplay_parallelbus_send (mp_obj_t obj , display_byte_type_t byte_type ,
176179 display_chip_select_behavior_t chip_select , const uint8_t * data , uint32_t data_length ) {
177180 paralleldisplay_parallelbus_obj_t * self = MP_OBJ_TO_PTR (obj );
178- common_hal_digitalio_digitalinout_set_value (& self -> command , byte_type == DISPLAY_DATA );
179-
180- uint32_t * clear_write = self -> write_clear_register ;
181- uint32_t * set_write = self -> write_set_register ;
182-
183- const uint32_t mask = self -> write_mask ;
184-
185- /* Setup structures for data writing. The ESP32-S2 port differs from the SAMD and NRF ports
186- * because I have not found a way to write a single byte into the ESP32-S2 registers.
187- * For the ESP32-S2, I create a 32-bit data_buffer that is used to transfer the data bytes.
188- */
189-
190- * clear_write = mask ; // Clear the write pin to prepare the registers before storing the
191- // register value into data_buffer
192-
193- const uint32_t data_buffer = * self -> bus ; // store the initial output register values into the data output buffer
194- uint8_t * data_address = ((uint8_t * )& data_buffer ) + (self -> data0_pin / 8 ); /* address inside data_buffer where
195- * each data byte will be written to the data pin registers
196- */
197-
198-
199- if (self -> data_write_same_register ) { // data and write pins are on the same register
200- for (uint32_t i = 0 ; i < data_length ; i ++ ) {
201-
202- /* Note: If the write pin and data pins are controlled by the same GPIO register, we can eliminate
203- * the "clear_write" step below, since the write pin is cleared when the data_buffer is written
204- * to the bus.
205- */
206-
207- * (data_address ) = data [i ]; // stuff the data byte into the data_buffer at the correct offset byte location
208- * self -> bus = data_buffer ; // write the data to the output register
209- * set_write = mask ; // set the write pin
210- }
211- } else { // data and write pins are on different registers
212- for (uint32_t i = 0 ; i < data_length ; i ++ ) {
213- * clear_write = mask ; // clear the write pin (See comment above, this may not be necessary).
214- * (data_address ) = data [i ]; // stuff the data byte into the data_buffer at the correct offset byte location
215- * self -> bus = data_buffer ; // write the data to the output register
216- * set_write = mask ; // set the write pin
217-
218- }
181+ if (data_length ) {
182+ gpio_set_level (self -> config .pin_num_rs , byte_type == DISPLAY_DATA );
183+ i2s_lcd_write (self -> handle , data , data_length );
219184 }
220-
221185}
222186
223187void common_hal_paralleldisplay_parallelbus_end_transaction (mp_obj_t obj ) {
224- /* SNIP - same as from SAMD and NRF ports */
225188 paralleldisplay_parallelbus_obj_t * self = MP_OBJ_TO_PTR (obj );
226- common_hal_digitalio_digitalinout_set_value (& self -> chip_select , true);
189+ i2s_lcd_release (self -> handle );
190+ gpio_set_level (self -> config .pin_num_cs , true);
227191}
0 commit comments