24
24
* THE SOFTWARE.
25
25
*/
26
26
27
- #include "shared-bindings/paralleldisplay/ParallelBus.h"
28
-
29
27
#include <stdint.h>
28
+ #include <string.h>
30
29
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"
33
32
#include "shared-bindings/digitalio/DigitalInOut.h"
34
33
#include "shared-bindings/microcontroller/__init__.h"
35
34
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"
36
41
/*
37
42
* Current pin limitations for ESP32-S2 ParallelBus:
38
43
* - data0 pin must be byte aligned
39
44
*/
40
45
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 ,
43
49
const mcu_pin_obj_t * write , const mcu_pin_obj_t * read , const mcu_pin_obj_t * reset , uint32_t frequency ) {
44
50
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 );
48
53
}
49
54
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 ] )) {
52
57
mp_raise_ValueError_varg (translate ("Bus pin %d is already in use" ), i );
53
58
}
54
59
}
55
60
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 ();
57
63
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
+ };
66
74
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 ;
74
78
} else {
75
- self -> bus = ( uint32_t * ) & g -> out1 . val ; // pointer to GPIO output register (for pins >= 32)
79
+ self -> reset_pin_number = NO_PIN ;
76
80
}
77
81
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 ]);
103
85
}
104
86
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);
111
99
}
112
100
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 );
113
106
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 );
115
109
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" ));
124
113
}
114
+ }
125
115
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
- }
133
116
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 );
134
127
}
135
128
129
+
136
130
void 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 ;
137
136
/* 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 ] );
140
139
}
141
140
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 );
147
148
}
148
149
149
150
bool common_hal_paralleldisplay_parallelbus_reset (mp_obj_t obj ) {
150
151
/* SNIP - same as from SAMD and NRF ports */
151
152
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 ) {
153
154
return false;
154
155
}
155
156
156
- common_hal_digitalio_digitalinout_set_value ( & self -> reset , false);
157
+ gpio_set_level ( self -> reset_pin_number , false);
157
158
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);
159
160
return true;
160
161
161
162
}
@@ -166,62 +167,25 @@ bool common_hal_paralleldisplay_parallelbus_bus_free(mp_obj_t obj) {
166
167
}
167
168
168
169
bool common_hal_paralleldisplay_parallelbus_begin_transaction (mp_obj_t obj ) {
169
- /* SNIP - same as from SAMD and NRF ports */
170
170
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 ;
173
176
}
174
177
175
178
void common_hal_paralleldisplay_parallelbus_send (mp_obj_t obj , display_byte_type_t byte_type ,
176
179
display_chip_select_behavior_t chip_select , const uint8_t * data , uint32_t data_length ) {
177
180
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 );
219
184
}
220
-
221
185
}
222
186
223
187
void common_hal_paralleldisplay_parallelbus_end_transaction (mp_obj_t obj ) {
224
- /* SNIP - same as from SAMD and NRF ports */
225
188
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);
227
191
}
0 commit comments