M5Unified
M5Unified.cpp
Go to the documentation of this file.
1 // Copyright (c) M5Stack. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
5 
6 #include "M5Unified.hpp"
7 
8 #if !defined (M5UNIFIED_PC_BUILD)
9 #include <soc/efuse_reg.h>
10 #include <soc/gpio_periph.h>
11 
12 #if __has_include (<driver/i2s.h>)
13 #include <driver/i2s.h>
14 #endif
15 
16 #if __has_include (<esp_idf_version.h>)
17  #include <esp_idf_version.h>
18  #if ESP_IDF_VERSION_MAJOR >= 4
20  #define NON_BREAK ;[[fallthrough]];
21  #endif
22 
23 #endif
24 #endif
25 
27 #ifndef NON_BREAK
28 #define NON_BREAK ;
29 #endif
30 
33 
34 void __attribute((weak)) adc_power_acquire(void)
35 {
36 #if !defined (M5UNIFIED_PC_BUILD)
37 #if defined (ESP_IDF_VERSION_VAL)
38  #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(3, 3, 4)
39  adc_power_on();
40  #endif
41 #else
42  adc_power_on();
43 #endif
44 #endif
45 }
46 
47 namespace m5
48 {
49 int8_t M5Unified::_get_pin_table[pin_name_max];
50 // ピン番号テーブル。 unknownをテーブルの最後に配置する。該当が無い場合はunknownの値が使用される。
51 static constexpr const uint8_t _pin_table_i2c_ex_in[][5] = {
52  // In CL,DA, EX CL,DA
53 #if defined (CONFIG_IDF_TARGET_ESP32S3)
54 { board_t::board_M5StackCoreS3, 11,12 , 1, 2 },
55 { board_t::board_M5StampS3 ,255,255, 15,13 },
56 { board_t::board_M5Capsule , 10, 8 , 15,13 },
57 { board_t::board_M5Dial , 12,11 , 15,13 },
58 { board_t::board_M5DinMeter , 12,11 , 15,13 },
59 { board_t::board_M5Cardputer ,255,255, 1, 2 },
60 { board_t::board_unknown , 39,38 , 1, 2 }, // AtomS3,AtomS3Lite,AtomS3U
61 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
62 { board_t::board_unknown ,255,255, 0, 1 },
63 #else
64 { board_t::board_M5Stack , 22,21, 22,21 },
65 { board_t::board_M5Paper , 22,21, 32,25 },
66 { board_t::board_M5TimerCam , 14,12, 13, 4 },
67 { board_t::board_M5Atom , 21,25, 32,26 },
68 { board_t::board_M5AtomU , 21,25, 32,26 },
69 { board_t::board_M5AtomPsram , 21,25, 32,26 },
70 { board_t::board_unknown , 22,21, 33,32 }, // Core2,Tough,StickC,CoreInk,Station,StampPico
71 #endif
72 };
73 
74 static constexpr const uint8_t _pin_table_port_bc[][5] = {
75  //pB p1,p2, pC p1,p2
76 #if defined (CONFIG_IDF_TARGET_ESP32S3)
77 { board_t::board_M5StackCoreS3, 8, 9, 18,17 },
78 { board_t::board_M5Dial , 1, 2, 255,255 },
79 { board_t::board_M5DinMeter , 1, 2, 255,255 },
80 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
81 #else
82 { board_t::board_M5Stack , 36,26, 16,17 },
83 { board_t::board_M5StackCore2 , 36,26, 13,14 },
84 { board_t::board_M5Paper , 33,26, 19,18 },
85 { board_t::board_M5Station , 35,25, 13,14 },
86 #endif
87 { board_t::board_unknown , 255,255, 255,255 },
88 };
89 
90 static constexpr const uint8_t _pin_table_port_de[][5] = {
91  //pD p1,p2, pE p1,p2
92 #if defined (CONFIG_IDF_TARGET_ESP32S3)
93 { board_t::board_M5StackCoreS3, 14,10, 18,17 },
94 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
95 #else
96 { board_t::board_M5Stack , 34,35, 5,13 },
97 { board_t::board_M5StackCore2 , 34,35, 27,19 },
98 { board_t::board_M5Station , 36,26, 16,17 }, // B2 / C2
99 #endif
100 { board_t::board_unknown , 255,255, 255,255 },
101 };
102 
103 static constexpr const uint8_t _pin_table_spi_sd[][5] = {
104  // clk,mosi,miso,cs
105 #if defined (CONFIG_IDF_TARGET_ESP32S3)
106 { board_t::board_M5StackCoreS3, 36, 37, 35, 4 },
107 { board_t::board_M5Capsule , 14, 12, 39, 11 },
108 { board_t::board_M5Cardputer , 40, 14, 39, 12 },
109 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
110 #else
111 { board_t::board_M5Stack , 18, 23, 19, 4 },
112 { board_t::board_M5StackCore2 , 18, 23, 38, 4 },
113 { board_t::board_M5Paper , 14, 12, 13, 4 },
114 #endif
115 { board_t::board_unknown , 255,255, 255,255 },
116 };
117 
118 static constexpr const uint8_t _pin_table_other[][2] = {
119  //RGBLED
120 #if defined (CONFIG_IDF_TARGET_ESP32S3)
121 { board_t::board_M5AtomS3U , 35 },
122 { board_t::board_M5AtomS3Lite , 35 },
123 { board_t::board_M5StampS3 , 21 },
124 { board_t::board_M5Capsule , 21 },
125 { board_t::board_M5Cardputer , 21 },
126 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
127 { board_t::board_M5StampC3 , 2 },
128 { board_t::board_M5StampC3U , 2 },
129 #else
130 { board_t::board_M5Stack , 15 },
131 { board_t::board_M5StackCore2 , 25 },
132 { board_t::board_M5Station , 4 },
133 { board_t::board_M5Atom , 27 },
134 { board_t::board_M5AtomU , 27 },
135 { board_t::board_M5AtomPsram , 27 },
136 { board_t::board_M5StampPico , 27 },
137 #endif
138 { board_t::board_unknown , 255 },
139 };
140 
141  void M5Unified::_setup_pinmap(board_t id)
142  {
143  constexpr const std::pair<const void*, size_t> tbl[] = {
144  { _pin_table_i2c_ex_in, sizeof(_pin_table_i2c_ex_in[0]) },
145  { _pin_table_port_bc, sizeof(_pin_table_port_bc[0]) },
146  { _pin_table_port_de, sizeof(_pin_table_port_de[0]) },
147  { _pin_table_spi_sd, sizeof(_pin_table_spi_sd[0]) },
148  { _pin_table_other, sizeof(_pin_table_other[0]) },
149  };
150 
151  int8_t* dst = _get_pin_table;
152  for (auto &p : tbl) {
153  const uint8_t* t = (uint8_t*)p.first;
154  size_t len = p.second;
155  while (t[0] != id && t[0] != board_t::board_unknown) { t += len; }
156  memcpy(dst, &t[1], len - 1);
157  dst += len - 1;
158  }
159  }
160 
161 #if defined (CONFIG_IDF_TARGET_ESP32S3)
162  static constexpr uint8_t aw88298_i2c_addr = 0x36;
163  static constexpr uint8_t es7210_i2c_addr = 0x40;
164  static constexpr uint8_t aw9523_i2c_addr = 0x58;
165  static void aw88298_write_reg(uint8_t reg, uint16_t value)
166  {
167  value = __builtin_bswap16(value);
168  M5.In_I2C.writeRegister(aw88298_i2c_addr, reg, (const uint8_t*)&value, 2, 400000);
169  }
170 
171  static void es7210_write_reg(uint8_t reg, uint8_t value)
172  {
173  M5.In_I2C.writeRegister(es7210_i2c_addr, reg, &value, 1, 400000);
174  }
175 
176 #endif
177 
178  bool M5Unified::_speaker_enabled_cb(void* args, bool enabled)
179  {
180  auto self = (M5Unified*)args;
181 
182  switch (self->getBoard())
183  {
184 #if defined (M5UNIFIED_PC_BUILD)
185 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
186  case board_t::board_M5StackCoreS3:
187  {
188  auto cfg = self->Speaker.config();
189  if (cfg.pin_bck == GPIO_NUM_34 && enabled)
190  {
191  self->In_I2C.bitOn(aw9523_i2c_addr, 0x02, 0b00000100, 400000);
193  static constexpr uint8_t rate_tbl[] = {4,5,6,8,10,11,15,20,22,44};
194  size_t reg0x06_value = 0;
195  size_t rate = (cfg.sample_rate + 1102) / 2205;
196  while (rate > rate_tbl[reg0x06_value] && ++reg0x06_value < sizeof(rate_tbl)) {}
197 
198  reg0x06_value |= 0x14C0; // I2SBCK=0 (BCK mode 16*2)
199  aw88298_write_reg( 0x61, 0x0673 ); // boost mode disabled
200  aw88298_write_reg( 0x04, 0x4040 ); // I2SEN=1 AMPPD=0 PWDN=0
201  aw88298_write_reg( 0x05, 0x0008 ); // RMSE=0 HAGCE=0 HDCCE=0 HMUTE=0
202  aw88298_write_reg( 0x06, reg0x06_value );
203  aw88298_write_reg( 0x0C, 0x0064 ); // volume setting (full volume)
204  }
205  else
206  {
207  aw88298_write_reg( 0x04, 0x4000 ); // I2SEN=0 AMPPD=0 PWDN=0
208  self->In_I2C.bitOff(aw9523_i2c_addr, 0x02, 0b00000100, 400000);
209  }
210  }
211  break;
212 
213 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
214  case board_t::board_M5StackCore2:
215  case board_t::board_M5Tough:
216  {
217  auto spk_cfg = self->Speaker.config();
218  if (spk_cfg.pin_bck == GPIO_NUM_12
219  && spk_cfg.pin_ws == GPIO_NUM_0
220  && spk_cfg.pin_data_out == GPIO_NUM_2
221  ) {
222  switch (self->Power.getType()) {
224  self->Power.Axp192.setGPIO2(enabled);
225  break;
227  self->Power.Axp2101.setALDO3(enabled * 3300);
228  break;
229  default:
230  break;
231  }
232  }
233  }
234  break;
235 
236  case board_t::board_M5StickC:
237  case board_t::board_M5StickCPlus:
238  case board_t::board_M5StickCPlus2:
239  case board_t::board_M5StackCoreInk:
241  if (self->use_hat_spk)
242  {
243  gpio_num_t pin_en = self->_board == board_t::board_M5StackCoreInk ? GPIO_NUM_25 : GPIO_NUM_0;
244  if (enabled)
245  {
246  m5gfx::pinMode(pin_en, m5gfx::pin_mode_t::output);
247  m5gfx::gpio_hi(pin_en);
248  }
249  else
250  { m5gfx::gpio_lo(pin_en); }
251  }
252  break;
253 
254 #endif
255  default:
256  break;
257  }
258  return true;
259  }
260 
261  bool M5Unified::_microphone_enabled_cb(void* args, bool enabled)
262  {
263  auto self = (M5Unified*)args;
264 
265  switch (self->getBoard())
266  {
267 #if defined (M5UNIFIED_PC_BUILD)
268 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
269  case board_t::board_M5StackCoreS3:
270  {
271  auto cfg = self->Mic.config();
272  if (cfg.pin_bck == GPIO_NUM_34)
273  {
274  es7210_write_reg(0x00, 0xFF); // RESET_CTL
275  struct __attribute__((packed)) reg_data_t
276  {
277  uint8_t reg;
278  uint8_t value;
279  };
280  if (enabled)
281  {
282  static constexpr reg_data_t data[] =
283  {
284  { 0x00, 0x41 }, // RESET_CTL
285  { 0x01, 0x1f }, // CLK_ON_OFF
286  { 0x06, 0x00 }, // DIGITAL_PDN
287  { 0x07, 0x20 }, // ADC_OSR
288  { 0x08, 0x10 }, // MODE_CFG
289  { 0x09, 0x30 }, // TCT0_CHPINI
290  { 0x0A, 0x30 }, // TCT1_CHPINI
291  { 0x20, 0x0a }, // ADC34_HPF2
292  { 0x21, 0x2a }, // ADC34_HPF1
293  { 0x22, 0x0a }, // ADC12_HPF2
294  { 0x23, 0x2a }, // ADC12_HPF1
295  { 0x02, 0xC1 },
296  { 0x04, 0x01 },
297  { 0x05, 0x00 },
298  { 0x11, 0x60 },
299  { 0x40, 0x42 }, // ANALOG_SYS
300  { 0x41, 0x70 }, // MICBIAS12
301  { 0x42, 0x70 }, // MICBIAS34
302  { 0x43, 0x1B }, // MIC1_GAIN
303  { 0x44, 0x1B }, // MIC2_GAIN
304  { 0x45, 0x00 }, // MIC3_GAIN
305  { 0x46, 0x00 }, // MIC4_GAIN
306  { 0x47, 0x00 }, // MIC1_LP
307  { 0x48, 0x00 }, // MIC2_LP
308  { 0x49, 0x00 }, // MIC3_LP
309  { 0x4A, 0x00 }, // MIC4_LP
310  { 0x4B, 0x00 }, // MIC12_PDN
311  { 0x4C, 0xFF }, // MIC34_PDN
312  { 0x01, 0x14 }, // CLK_ON_OFF
313  };
314  for (auto& d: data)
315  {
316  es7210_write_reg(d.reg, d.value);
317  }
318  }
319 /*
320 uint8_t buf[0x50];
321 for (int i = 0; i < 0x50; ++i)
322 {
323  self->In_I2C.readRegister(es7210_i2c_addr, i, &buf[i], 1, 400000);
324  if ((i & 15) == 15)
325  {
326  auto d = &buf[i-15];
327  ESP_LOGE("DEBUG","%02x :%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
328  ,i>>4 , d[ 0], d[ 1], d[ 2], d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], d[ 9], d[10], d[11], d[12], d[13], d[14], d[15]);
329  }
330 }
331 //*/
332  }
333  }
334  break;
335 
336 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
337  case board_t::board_M5StickC:
338  case board_t::board_M5StickCPlus:
339  self->Power.Axp192.setLDO0(enabled ? 2800 : 0);
340  break;
341 
342 #endif
343  default:
344  break;
345  }
346  return true;
347  }
348 
349 #if defined (M5UNIFIED_PC_BUILD)
350 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
351  static constexpr gpio_num_t TFCARD_CS_PIN = GPIO_NUM_4;
352  static constexpr gpio_num_t CoreInk_BUTTON_EXT_PIN = GPIO_NUM_5;
353  static constexpr gpio_num_t CoreInk_BUTTON_PWR_PIN = GPIO_NUM_27;
354 #endif
355 
356  board_t M5Unified::_check_boardtype(board_t board)
357  {
358 #if defined (M5UNIFIED_PC_BUILD)
359 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
360  if (board == board_t::board_unknown)
361  {
362  switch (m5gfx::get_pkg_ver())
363  {
364  case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6:
365  board = board_t::board_M5TimerCam;
366  break;
367 
368  case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4:
369  m5gfx::pinMode(GPIO_NUM_2, m5gfx::pin_mode_t::input_pullup);
370  m5gfx::pinMode(GPIO_NUM_34, m5gfx::pin_mode_t::input);
371  board = m5gfx::gpio_in(GPIO_NUM_2)
372  ? (m5gfx::gpio_in(GPIO_NUM_34) ? board_t::board_M5Atom : board_t::board_M5AtomU)
373  : board_t::board_M5StampPico;
374  m5gfx::pinMode(GPIO_NUM_2, m5gfx::pin_mode_t::input_pulldown);
375  break;
376 
377  case 6: // EFUSE_RD_CHIP_VER_PKG_ESP32PICOV3_02: // ATOM PSRAM
378  board = board_t::board_M5AtomPsram;
379  break;
380 
381  default:
382 
383 #if defined ( ARDUINO_M5STACK_CORE_ESP32 ) || defined ( ARDUINO_M5STACK_FIRE ) || defined ( ARDUINO_M5Stack_Core_ESP32 )
384 
385  board = board_t::board_M5Stack;
386 
387 #elif defined ( ARDUINO_M5STACK_CORE2 ) || defined ( ARDUINO_M5STACK_Core2 )
388 
389  board = board_t::board_M5StackCore2;
390 
391 #elif defined ( ARDUINO_M5STICK_C ) || defined ( ARDUINO_M5Stick_C )
392 
393  board = board_t::board_M5StickC;
394 
395 #elif defined ( ARDUINO_M5STICK_C_PLUS ) || defined ( ARDUINO_M5Stick_C_Plus )
396 
397  board = board_t::board_M5StickCPlus;
398 
399 #elif defined ( ARDUINO_M5STACK_COREINK ) || defined ( ARDUINO_M5Stack_CoreInk )
400 
401  board = board_t::board_M5StackCoreInk;
402 
403 #elif defined ( ARDUINO_M5STACK_PAPER ) || defined ( ARDUINO_M5STACK_Paper )
404 
405  board = board_t::board_M5Paper;
406 
407 #elif defined ( ARDUINO_M5STACK_TOUGH )
408 
409  board = board_t::board_M5Tough;
410 
411 #elif defined ( ARDUINO_M5STACK_ATOM ) || defined ( ARDUINO_M5Stack_ATOM )
412 
413  board = board_t::board_M5Atom;
414 
415 #elif defined ( ARDUINO_M5STACK_TIMER_CAM ) || defined ( ARDUINO_M5Stack_Timer_CAM )
416 
417  board = board_t::board_M5TimerCam;
418 
419 #endif
420  break;
421  }
422  }
423 
424 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
425  if (board == board_t::board_unknown)
426  {
435 
436  m5gfx::gpio::pin_backup_t pin_backup[] = { GPIO_NUM_4, GPIO_NUM_8, GPIO_NUM_10, GPIO_NUM_12, GPIO_NUM_38 };
437  auto result = m5gfx::gpio::command(
438  (const uint8_t[]) {
439  m5gfx::gpio::command_mode_input_pulldown, GPIO_NUM_4,
440  m5gfx::gpio::command_mode_input_pulldown, GPIO_NUM_12,
441  m5gfx::gpio::command_mode_input_pulldown, GPIO_NUM_38,
442  m5gfx::gpio::command_mode_input_pulldown, GPIO_NUM_8,
443  m5gfx::gpio::command_mode_input_pulldown, GPIO_NUM_10,
444  m5gfx::gpio::command_mode_input_pullup , GPIO_NUM_4,
445  m5gfx::gpio::command_mode_input_pullup , GPIO_NUM_12,
446  m5gfx::gpio::command_mode_input_pullup , GPIO_NUM_38,
447  m5gfx::gpio::command_read , GPIO_NUM_8,
448  m5gfx::gpio::command_read , GPIO_NUM_10,
449  m5gfx::gpio::command_read , GPIO_NUM_4,
450  m5gfx::gpio::command_read , GPIO_NUM_12,
451  m5gfx::gpio::command_read , GPIO_NUM_38,
452  m5gfx::gpio::command_mode_input , GPIO_NUM_38,
453  m5gfx::gpio::command_delay , 1,
454  m5gfx::gpio::command_read , GPIO_NUM_38,
455  m5gfx::gpio::command_end
456  }
457  );
459  board = ((const board_t[])
460  { // ↓StampS3 pattern↓
461  board_t::board_unknown, board_t::board_unknown, board_t::board_M5StampS3, board_t::board_unknown, // ← unknown
462  board_t::board_M5AtomS3Lite,board_t::board_M5AtomS3Lite,board_t::board_M5StampS3, board_t::board_M5AtomS3Lite, // ← AtomS3Lite pattern
463  board_t::board_M5AtomS3U, board_t::board_M5AtomS3U, board_t::board_M5StampS3, board_t::board_M5AtomS3U, // ← AtomS3U pattern
464  board_t::board_unknown, board_t::board_unknown, board_t::board_M5StampS3, board_t::board_unknown, // ← unknown
465  })[result&15];
466  if (board == board_t::board_M5StampS3) {
467  if ((result >> 3) == 0b110) { board = board_t::board_M5Capsule; }
468  }
469  for (auto &backup : pin_backup) {
470  backup.restore();
471  }
472  }
473 
474 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
475  if (board == board_t::board_unknown)
476  { // StampC3 or StampC3U ?
477  uint32_t tmp = *((volatile uint32_t *)(IO_MUX_GPIO20_REG));
478  m5gfx::pinMode(GPIO_NUM_20, m5gfx::pin_mode_t::input_pulldown);
479  // StampC3 has a strong external pull-up on GPIO20, which is HIGH even when input_pulldown is set.
480  // Therefore, if it is LOW, it is not StampC3 and can be assumed to be StampC3U.
481  // However, even if it goes HIGH, something may be connected to GPIO20 by StampC3U, so it is treated as unknown.
482  // The StampC3U determination uses the fallback_board setting.
483  if (m5gfx::gpio_in(GPIO_NUM_20) == false)
484  {
485  board = board_t::board_M5StampC3U;
486  }
487  *((volatile uint32_t *)(IO_MUX_GPIO20_REG)) = tmp;
488  }
489 
490 #endif
491 
492  return board;
493  }
494 
495  void M5Unified::_setup_i2c(board_t board)
496  {
497 #if !defined (M5UNIFIED_PC_BUILD)
498 
499  gpio_num_t in_scl = (gpio_num_t)getPin(pin_name_t::in_i2c_scl);
500  gpio_num_t in_sda = (gpio_num_t)getPin(pin_name_t::in_i2c_sda);
501  gpio_num_t ex_scl = (gpio_num_t)getPin(pin_name_t::ex_i2c_scl);
502  gpio_num_t ex_sda = (gpio_num_t)getPin(pin_name_t::ex_i2c_sda);
503 
504  i2c_port_t ex_port = I2C_NUM_0;
505 #if defined (CONFIG_IDF_TARGET_ESP32C3)
506  i2c_port_t in_port = I2C_NUM_0;
507 #else
508  i2c_port_t in_port = I2C_NUM_1;
509  if (in_scl == ex_scl && in_sda == ex_sda) {
510  in_port = ex_port;
511  }
512 #endif
513  if ((int)in_scl >= 0)
514  {
515  In_I2C.begin(in_port, in_sda, in_scl);
516  }
517  else
518  {
519  In_I2C.setPort(I2C_NUM_MAX, in_sda, in_scl);
520  }
521 
522  if ((int)ex_scl >= 0)
523  {
524  Ex_I2C.setPort(ex_port, ex_sda, ex_scl);
525  }
526 #endif
527 
528  }
529 
530  void M5Unified::_begin(const config_t& cfg)
531  {
533  Power.begin();
534  Power.setExtOutput(cfg.output_power);
535  if (cfg.led_brightness)
536  {
537  M5.Power.setLed(cfg.led_brightness);
538  }
539  if (Power.getType() == Power_Class::pmic_t::pmic_axp2101
540  || Power.getType() == Power_Class::pmic_t::pmic_axp192)
541  {
542  use_pmic_button = cfg.pmic_button;
545  }
546 
547  if (cfg.clear_display)
548  {
549  Display.clear();
550  }
551 
552 #if defined (M5UNIFIED_PC_BUILD)
553 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
554  switch (_board)
555  {
556  case board_t::board_M5Stack:
557  // Countermeasure to the problem that GPIO15 affects WiFi sensitivity when M5GO bottom is connected.
558  m5gfx::pinMode(GPIO_NUM_15, m5gfx::pin_mode_t::output);
559  m5gfx::gpio_lo(GPIO_NUM_15);
560 
561  // M5Stack Core v2.6 has a problem that SPI communication speed cannot be increased.
562  // This problem can be solved by increasing the GPIO drive current.
563  // ※ This allows SunDisk SD cards to communicate at 20 MHz. (without M5GO bottom.)
564  // This allows communication with ModuleDisplay at 80 MHz.
565  for (auto gpio: (const gpio_num_t[]){ GPIO_NUM_18, GPIO_NUM_19, GPIO_NUM_23 })
566  {
567  *(volatile uint32_t*)(GPIO_PIN_MUX_REG[gpio]) |= FUN_DRV_M; // gpio drive current set to 40mA.
568  gpio_pulldown_dis(gpio); // disable pulldown.
569  gpio_pullup_en(gpio); // enable pullup.
570  }
571  break;
572 
573  case board_t::board_M5StickC:
574  case board_t::board_M5StickCPlus:
575  case board_t::board_M5Atom:
576  case board_t::board_M5AtomU:
577  // Countermeasure to the problem that CH552 applies 4v to GPIO0, thus reducing WiFi sensitivity.
578  // Setting output_high adds a bias of 3.3v and suppresses overvoltage.
579  m5gfx::pinMode(GPIO_NUM_0, m5gfx::pin_mode_t::output);
580  m5gfx::gpio_hi(GPIO_NUM_0);
581  break;
582 
583  default:
584  break;
585  }
586 #endif
587 
588 #if defined ( ARDUINO )
589 
590  if (cfg.serial_baudrate)
591  { // Wait with delay to prevent startup log output from disappearing.
592  delay(16);
593  Serial.begin(cfg.serial_baudrate);
594  }
595 
596 #endif
597 
598  switch (_board)
599  {
600 #if defined (M5UNIFIED_PC_BUILD)
601 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
602  case board_t::board_M5StackCoreInk:
603  m5gfx::pinMode(CoreInk_BUTTON_EXT_PIN, m5gfx::pin_mode_t::input); // TopButton
604  m5gfx::pinMode(CoreInk_BUTTON_PWR_PIN, m5gfx::pin_mode_t::input); // PowerButton
605  NON_BREAK;
606 
607  case board_t::board_M5Paper:
608  case board_t::board_M5Station:
609  case board_t::board_M5Stack:
610  m5gfx::pinMode(GPIO_NUM_38, m5gfx::pin_mode_t::input);
611  NON_BREAK;
612 
613  case board_t::board_M5StickC:
614  case board_t::board_M5StickCPlus:
615  m5gfx::pinMode(GPIO_NUM_37, m5gfx::pin_mode_t::input);
616  NON_BREAK;
617 
618  case board_t::board_M5Atom:
619  case board_t::board_M5AtomPsram:
620  case board_t::board_M5AtomU:
621  case board_t::board_M5StampPico:
622  m5gfx::pinMode(GPIO_NUM_39, m5gfx::pin_mode_t::input);
623  NON_BREAK;
624 
625  case board_t::board_M5StackCore2:
626  case board_t::board_M5Tough:
628  adc_power_acquire();
629  break;
630 
631  case board_t::board_M5StickCPlus2:
632  m5gfx::pinMode(GPIO_NUM_35, m5gfx::pin_mode_t::input);
633  m5gfx::pinMode(GPIO_NUM_37, m5gfx::pin_mode_t::input);
634  m5gfx::pinMode(GPIO_NUM_39, m5gfx::pin_mode_t::input);
635  break;
636 
637 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
638 
639  case board_t::board_M5StampC3:
640  m5gfx::pinMode(GPIO_NUM_3, m5gfx::pin_mode_t::input_pullup);
641  break;
642 
643  case board_t::board_M5StampC3U:
644  m5gfx::pinMode(GPIO_NUM_9, m5gfx::pin_mode_t::input_pullup);
645  break;
646 
647 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
648  case board_t::board_M5AtomS3:
649  case board_t::board_M5AtomS3Lite:
650  case board_t::board_M5AtomS3U:
651  m5gfx::pinMode(GPIO_NUM_41, m5gfx::pin_mode_t::input);
652  break;
653 
654  case board_t::board_M5StampS3:
655  case board_t::board_M5Cardputer:
656  m5gfx::pinMode(GPIO_NUM_0, m5gfx::pin_mode_t::input);
657  break;
658 
659  case board_t::board_M5Capsule:
660  case board_t::board_M5Dial:
661  case board_t::board_M5DinMeter:
662  m5gfx::pinMode(GPIO_NUM_42, m5gfx::pin_mode_t::input);
663  break;
664 
665 #endif
666 
667  default:
668  break;
669  }
670  }
671 
672  void M5Unified::_begin_spk(config_t& cfg)
673  {
674  if (cfg.internal_mic)
675  {
676  auto mic_cfg = Mic.config();
677 
678  mic_cfg.over_sampling = 1;
679  mic_cfg.i2s_port = I2S_NUM_0;
680  switch (_board)
681  {
682 #if defined (M5UNIFIED_PC_BUILD)
683 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
684  case board_t::board_M5StackCoreS3:
685  if (cfg.internal_mic)
686  {
687  mic_cfg.magnification = 2;
688  mic_cfg.over_sampling = 1;
689  mic_cfg.pin_mck = GPIO_NUM_0;
690  mic_cfg.pin_bck = GPIO_NUM_34;
691  mic_cfg.pin_ws = GPIO_NUM_33;
692  mic_cfg.pin_data_in = GPIO_NUM_14;
693  mic_cfg.i2s_port = I2S_NUM_1;
694  mic_cfg.stereo = true;
695  }
696  break;
697 
698  case board_t::board_M5AtomS3U:
699  if (cfg.internal_mic)
700  {
701  mic_cfg.pin_data_in = GPIO_NUM_38;
702  mic_cfg.pin_ws = GPIO_NUM_39;
703  }
704  break;
705 
706  case board_t::board_M5Cardputer:
707  if (cfg.internal_mic)
708  {
709  mic_cfg.pin_data_in = GPIO_NUM_46;
710  mic_cfg.pin_ws = GPIO_NUM_43;
711  }
712  break;
713 
714  case board_t::board_M5Capsule:
715  if (cfg.internal_mic)
716  {
717  mic_cfg.pin_data_in = GPIO_NUM_41;
718  mic_cfg.pin_ws = GPIO_NUM_40;
719  }
720  break;
721 
722 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
723  case board_t::board_M5Stack:
724  if (cfg.internal_mic)
725  {
726  mic_cfg.pin_data_in = GPIO_NUM_34; // M5GO bottom MIC
727  mic_cfg.i2s_port = I2S_NUM_0;
728  mic_cfg.use_adc = true; // use ADC analog input
729  mic_cfg.over_sampling = 4;
730  }
731  break;
732 
733  case board_t::board_M5StickC:
734  case board_t::board_M5StickCPlus:
735  case board_t::board_M5StickCPlus2:
736  case board_t::board_M5Tough:
737  case board_t::board_M5StackCore2:
738  if (cfg.internal_mic)
739  {
740  mic_cfg.pin_data_in = GPIO_NUM_34;
741  mic_cfg.pin_ws = GPIO_NUM_0;
742  }
743  break;
744 
745  case board_t::board_M5AtomU:
746  {
747  mic_cfg.pin_data_in = GPIO_NUM_19;
748  mic_cfg.pin_ws = GPIO_NUM_5;
749  }
750  break;
751 
752  case board_t::board_M5Atom:
753  {
754  mic_cfg.pin_data_in = GPIO_NUM_23;
755  mic_cfg.pin_ws = GPIO_NUM_33;
756  }
757  break;
758 #endif
759  default:
760  break;
761  }
762  if (mic_cfg.pin_data_in >= 0)
763  {
764  Mic.setCallback(this, _microphone_enabled_cb);
765  Mic.config(mic_cfg);
766  }
767  }
768 
769  if (cfg.external_spk_detail.enabled && cfg.external_speaker_value == 0) {
770  cfg.external_speaker.atomic_spk = false==cfg.external_spk_detail.omit_atomic_spk;
771  cfg.external_speaker.hat_spk = false==cfg.external_spk_detail.omit_spk_hat;
772  }
773 
774  if (cfg.internal_spk || cfg.external_speaker_value)
775  {
776  auto spk_cfg = Speaker.config();
777  // set default speaker gain.
778  spk_cfg.magnification = 16;
779 #if defined SOC_I2S_NUM
780  spk_cfg.i2s_port = (i2s_port_t)(SOC_I2S_NUM - 1);
781 #else
782  spk_cfg.i2s_port = (i2s_port_t)(I2S_NUM_MAX - 1);
783 #endif
784  switch (_board)
785  {
786 #if defined (M5UNIFIED_PC_BUILD)
787 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
788  case board_t::board_M5StackCoreS3:
789  if (cfg.internal_spk)
790  {
791  spk_cfg.pin_bck = GPIO_NUM_34;
792  spk_cfg.pin_ws = GPIO_NUM_33;
793  spk_cfg.pin_data_out = GPIO_NUM_13;
794  spk_cfg.magnification = 4;
795  spk_cfg.i2s_port = I2S_NUM_1;
796  }
797  break;
798 
799  case board_t::board_M5AtomS3:
800  case board_t::board_M5AtomS3Lite:
801  if (cfg.external_speaker.atomic_spk && (Display.getBoard() != board_t::board_M5AtomDisplay))
802  { // for ATOMIC SPK
803  m5gfx::pinMode(GPIO_NUM_6, m5gfx::pin_mode_t::input_pulldown); // MOSI
804  m5gfx::pinMode(GPIO_NUM_7, m5gfx::pin_mode_t::input_pulldown); // SCLK
805  if (m5gfx::gpio_in(GPIO_NUM_6)
806  && m5gfx::gpio_in(GPIO_NUM_7))
807  {
808  ESP_LOGD("M5Unified", "ATOMIC SPK");
809  // atomic_spkのSDカード用ピンを割当
810  _get_pin_table[sd_spi_sclk] = GPIO_NUM_7;
811  _get_pin_table[sd_spi_copi] = GPIO_NUM_6;
812  _get_pin_table[sd_spi_cipo] = GPIO_NUM_8;
813  cfg.internal_imu = false;
814  cfg.internal_rtc = false;
815  spk_cfg.pin_bck = GPIO_NUM_5;
816  spk_cfg.pin_ws = GPIO_NUM_39;
817  spk_cfg.pin_data_out = GPIO_NUM_38;
818  spk_cfg.magnification = 16;
819  }
820  }
821  break;
822 
823  case board_t::board_M5Capsule:
824  if (cfg.internal_spk)
825  {
826  spk_cfg.pin_data_out = GPIO_NUM_2;
827  spk_cfg.buzzer = true;
828  spk_cfg.magnification = 48;
829  }
830  break;
831 
832  case board_t::board_M5Dial:
833  case board_t::board_M5DinMeter:
834  if (cfg.internal_spk)
835  {
836  spk_cfg.pin_data_out = GPIO_NUM_3;
837  spk_cfg.buzzer = true;
838  spk_cfg.magnification = 48;
839  }
840  break;
841 
842  case board_t::board_M5Cardputer:
843  if (cfg.internal_spk)
844  {
845  spk_cfg.pin_bck = GPIO_NUM_41;
846  spk_cfg.pin_ws = GPIO_NUM_43;
847  spk_cfg.pin_data_out = GPIO_NUM_42;
848  spk_cfg.magnification = 16;
849  spk_cfg.i2s_port = I2S_NUM_1;
850  }
851  break;
852 
853 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
854  case board_t::board_M5Stack:
855  if (cfg.internal_spk)
856  {
857  m5gfx::gpio_lo(GPIO_NUM_25);
858  m5gfx::pinMode(GPIO_NUM_25, m5gfx::pin_mode_t::output);
859  spk_cfg.i2s_port = I2S_NUM_0;
860  spk_cfg.use_dac = true;
861  spk_cfg.pin_data_out = GPIO_NUM_25;
862  spk_cfg.magnification = 8;
863  }
864  break;
865 
866  case board_t::board_M5StackCoreInk:
867  case board_t::board_M5StickCPlus:
868  case board_t::board_M5StickCPlus2:
869  if (cfg.internal_spk)
870  {
871  spk_cfg.buzzer = true;
872  spk_cfg.pin_data_out = GPIO_NUM_2;
873  spk_cfg.magnification = 48;
874  }
875  NON_BREAK;
876 
877  case board_t::board_M5StickC:
878  if (cfg.external_speaker.hat_spk2 && (_board != board_t::board_M5StackCoreInk))
879  {
880  spk_cfg.pin_data_out = GPIO_NUM_25;
881  spk_cfg.pin_bck = GPIO_NUM_26;
882  spk_cfg.pin_ws = GPIO_NUM_0;
883  spk_cfg.i2s_port = I2S_NUM_1;
884  spk_cfg.use_dac = false;
885  spk_cfg.buzzer = false;
886  spk_cfg.magnification = 16;
887  }
888  else if (cfg.external_speaker.hat_spk)
889  {
890  use_hat_spk = true;
891  gpio_num_t pin_en = _board == board_t::board_M5StackCoreInk ? GPIO_NUM_25 : GPIO_NUM_0;
892  m5gfx::gpio_lo(pin_en);
893  m5gfx::pinMode(pin_en, m5gfx::pin_mode_t::output);
894  m5gfx::gpio_lo(GPIO_NUM_26);
895  m5gfx::pinMode(GPIO_NUM_26, m5gfx::pin_mode_t::output);
896  spk_cfg.pin_data_out = GPIO_NUM_26;
897  spk_cfg.i2s_port = I2S_NUM_0;
898  spk_cfg.use_dac = true;
899  spk_cfg.buzzer = false;
900  spk_cfg.magnification = 32;
901  }
902  break;
903 
904  case board_t::board_M5Tough:
905  // The magnification is set higher than Core2 here because the waterproof case reduces the sound.;
906  spk_cfg.magnification = 24;
907  NON_BREAK;
908  case board_t::board_M5StackCore2:
909  if (cfg.internal_spk)
910  {
911  spk_cfg.pin_bck = GPIO_NUM_12;
912  spk_cfg.pin_ws = GPIO_NUM_0;
913  spk_cfg.pin_data_out = GPIO_NUM_2;
914  }
915  break;
916 
917  case board_t::board_M5Atom:
918  if (cfg.internal_spk && (Display.getBoard() != board_t::board_M5AtomDisplay))
919  { // for ATOM ECHO
920  spk_cfg.pin_bck = GPIO_NUM_19;
921  spk_cfg.pin_ws = GPIO_NUM_33;
922  spk_cfg.pin_data_out = GPIO_NUM_22;
923  spk_cfg.magnification = 12;
924  }
925  NON_BREAK;
926  case board_t::board_M5AtomPsram:
927  if (cfg.external_speaker.atomic_spk && (Display.getBoard() != board_t::board_M5AtomDisplay))
928  { // for ATOMIC SPK
929  // 19,23 pulldown read check ( all high = ATOMIC_SPK ? ) // MISO is not used for judgment as it changes depending on the state of the SD card.
930  gpio_num_t pin = (_board == board_t::board_M5AtomPsram) ? GPIO_NUM_5 : GPIO_NUM_23;
931  m5gfx::pinMode(GPIO_NUM_19, m5gfx::pin_mode_t::input_pulldown); // MOSI
932  m5gfx::pinMode(pin , m5gfx::pin_mode_t::input_pulldown); // SCLK
933  if (m5gfx::gpio_in(GPIO_NUM_19)
934  && m5gfx::gpio_in(pin ))
935  {
936  ESP_LOGD("M5Unified", "ATOMIC SPK");
937  // atomic_spkのSDカード用ピンを割当
938  _get_pin_table[sd_spi_sclk] = pin;
939  _get_pin_table[sd_spi_copi] = GPIO_NUM_19;
940  _get_pin_table[sd_spi_cipo] = GPIO_NUM_33;
941  cfg.internal_imu = false;
942  cfg.internal_rtc = false;
943  spk_cfg.pin_bck = GPIO_NUM_22;
944  spk_cfg.pin_ws = GPIO_NUM_21;
945  spk_cfg.pin_data_out = GPIO_NUM_25;
946  spk_cfg.magnification = 16;
947  auto mic = Mic.config();
948  mic.pin_data_in = -1; // disable mic for ECHO
949  Mic.config(mic);
950  }
951  }
952  break;
953 #endif
954  default:
955  break;
956  }
957 
958  if (cfg.external_speaker_value)
959  {
960 #if defined (M5UNIFIED_PC_BUILD)
961 #elif defined ( CONFIG_IDF_TARGET_ESP32S3 )
962  #define ENABLE_M5MODULE
963  if (_board == board_t::board_M5StackCoreS3)
964 #elif defined ( CONFIG_IDF_TARGET_ESP32 ) || !defined ( CONFIG_IDF_TARGET )
965  #define ENABLE_M5MODULE
966  if ( _board == board_t::board_M5Stack
967  || _board == board_t::board_M5StackCore2
968  || _board == board_t::board_M5Tough)
969 #endif
970  {
971 #ifdef ENABLE_M5MODULE
972  bool use_module_display = cfg.external_speaker.module_display
973  && (0 <= getDisplayIndex(m5gfx::board_M5ModuleDisplay));
974  if (use_module_display || cfg.external_speaker.module_rca)
975  {
976  if (use_module_display) {
977  spk_cfg.sample_rate = 48000; // Module Display audio output is fixed at 48 kHz
978  }
979  uint32_t pins_index = use_module_display;
980  #if defined ( CONFIG_IDF_TARGET_ESP32S3 )
981  static constexpr const uint8_t pins[][2] =
982  {// DOUT , BCK
983  { GPIO_NUM_13, GPIO_NUM_7 }, // CoreS3 + ModuleRCA
984  { GPIO_NUM_13, GPIO_NUM_6 }, // CoreS3 + ModuleDisplay
985  };
986  #else
987  static constexpr const uint8_t pins[][2] =
988  {// DOUT , BCK
989  { GPIO_NUM_2 , GPIO_NUM_19 }, // Core2 and Tough + ModuleRCA
990  { GPIO_NUM_2 , GPIO_NUM_27 }, // Core2 and Tough + ModuleDisplay
991  { GPIO_NUM_15, GPIO_NUM_13 }, // Core + ModuleRCA
992  { GPIO_NUM_15, GPIO_NUM_12 }, // Core + ModuleDisplay
993  };
994  // !core is (Core2 + Tough)
995  if (_board == m5::board_t::board_M5Stack) {
996  pins_index += 2;
997  }
998  #endif
999  spk_cfg.pin_data_out = pins[pins_index][0];
1000  spk_cfg.pin_bck = pins[pins_index][1];
1001  spk_cfg.i2s_port = I2S_NUM_1;
1002  spk_cfg.magnification = 16;
1003  spk_cfg.stereo = true;
1004  spk_cfg.buzzer = false;
1005  spk_cfg.use_dac = false;
1006  spk_cfg.pin_ws = GPIO_NUM_0; // LRCK
1007  }
1008  #undef ENABLE_M5MODULE
1009 #endif
1010  }
1011  }
1012 
1013  if (spk_cfg.pin_data_out >= 0)
1014  {
1015  Speaker.setCallback(this, _speaker_enabled_cb);
1016  Speaker.config(spk_cfg);
1017  }
1018  }
1019  }
1020 
1021  bool M5Unified::_begin_rtc_imu(const config_t& cfg)
1022  {
1023  bool port_a_used = false;
1024  if (cfg.external_rtc || cfg.external_imu)
1025  {
1026  M5.Ex_I2C.begin();
1027  }
1028 
1029  if (cfg.internal_rtc && In_I2C.isEnabled())
1030  {
1031  M5.Rtc.begin();
1032  }
1033  if (!M5.Rtc.isEnabled() && cfg.external_rtc)
1034  {
1035  port_a_used = M5.Rtc.begin(&M5.Ex_I2C);
1036  }
1037  if (M5.Rtc.isEnabled())
1038  {
1040  if (cfg.disable_rtc_irq) {
1041  M5.Rtc.disableIRQ();
1042  }
1043  }
1044 
1045  if (cfg.internal_imu && In_I2C.isEnabled())
1046  {
1047  M5.Imu.begin(&M5.In_I2C, M5.getBoard());
1048  }
1049  if (!M5.Imu.isEnabled() && cfg.external_imu)
1050  {
1051  port_a_used = M5.Imu.begin(&M5.Ex_I2C) || port_a_used;
1052  }
1053  return port_a_used;
1054  }
1055 
1056  void M5Unified::update( void )
1057  {
1058  auto ms = m5gfx::millis();
1059  _updateMsec = ms;
1060 
1061  if (Touch.isEnabled())
1062  {
1063  Touch.update(ms);
1064  }
1065 
1066 #if defined (M5UNIFIED_PC_BUILD)
1067  BtnA.setRawState(ms, !m5gfx::gpio_in(39));
1068  BtnB.setRawState(ms, !m5gfx::gpio_in(38));
1069  BtnC.setRawState(ms, !m5gfx::gpio_in(37));
1070  BtnPWR.setRawState(ms, !m5gfx::gpio_in(36));
1071 #elif !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
1072 
1073  uint_fast8_t raw_gpio32_39 = ~GPIO.in1.data;
1074  // uint_fast8_t raw_gpio37_40 = ~GPIO.in1.data >> 5;
1075  uint_fast8_t btn_bits = 0;
1076  switch (_board)
1077  {
1078  case board_t::board_M5StackCore2:
1079  {
1080  int i = Touch.getCount();
1081  while (--i >= 0)
1082  {
1083  auto raw = Touch.getTouchPointRaw(i);
1084  if (raw.y > 240)
1085  {
1086  auto det = Touch.getDetail(i);
1087  if (det.state & touch_state_t::touch)
1088  {
1089  if (BtnA.isPressed()) { btn_bits |= 1 << 0; }
1090  if (BtnB.isPressed()) { btn_bits |= 1 << 1; }
1091  if (BtnC.isPressed()) { btn_bits |= 1 << 2; }
1092  if (btn_bits || !(det.state & touch_state_t::mask_moving))
1093  {
1094  btn_bits |= 1 << ((raw.x - 2) / 107);
1095  }
1096  }
1097  }
1098  }
1099  }
1100  break;
1101 
1102  case board_t::board_M5StackCoreInk:
1103  {
1104  uint32_t raw_gpio0_31 = ~GPIO.in;
1105  BtnEXT.setRawState(ms, (raw_gpio0_31 & (1 << CoreInk_BUTTON_EXT_PIN)));
1106  BtnPWR.setRawState(ms, (raw_gpio0_31 & (1 << CoreInk_BUTTON_PWR_PIN)));
1107  }
1108  NON_BREAK;
1109 
1110  case board_t::board_M5Paper:
1111  case board_t::board_M5Station:
1112  btn_bits = (raw_gpio32_39 >> 5) & 0x07; // gpio37 A / gpio38 B / gpio39 C
1113  break;
1114 
1115  case board_t::board_M5Stack:
1116  btn_bits = ((raw_gpio32_39 >> 5) & 0x02) // gpio38 B
1117  + ((raw_gpio32_39 >> 3) & 0x04); // gpio37 C
1118  NON_BREAK;
1119 
1120  case board_t::board_M5Atom:
1121  case board_t::board_M5AtomPsram:
1122  case board_t::board_M5AtomU:
1123  case board_t::board_M5StampPico:
1124  btn_bits += (raw_gpio32_39 >> 7) & 0x01; // gpio39 A
1125  break;
1126 
1127  case board_t::board_M5StickC:
1128  case board_t::board_M5StickCPlus:
1129  btn_bits = ((raw_gpio32_39 >> 5) & 0x01) // gpio37 A
1130  + ((raw_gpio32_39 >> 6) & 0x02); // gpio39 B
1131  break;
1132 
1133  case board_t::board_M5StickCPlus2:
1134  btn_bits = ((raw_gpio32_39 >> 5) & 0x01) // gpio37 A
1135  + ((raw_gpio32_39 >> 6) & 0x02); // gpio39 B
1136  BtnPWR.setRawState(ms, raw_gpio32_39 & 0x08); // gpio35 PWR
1137  break;
1138 
1139  default:
1140  break;
1141  }
1142 
1143  BtnA.setRawState(ms, btn_bits & 1);
1144  BtnB.setRawState(ms, btn_bits & 2);
1145  BtnC.setRawState(ms, btn_bits & 4);
1146  if (use_pmic_button)
1147  {
1148  Button_Class::button_state_t state = Button_Class::button_state_t::state_nochange;
1149  bool read_axp = (ms - BtnPWR.getUpdateMsec()) >= BTNPWR_MIN_UPDATE_MSEC;
1150  if (read_axp || BtnPWR.getState())
1151  {
1152  switch (Power.getKeyState())
1153  {
1154  case 0: break;
1155  case 2: state = Button_Class::button_state_t::state_clicked; break;
1156  default: state = Button_Class::button_state_t::state_hold; break;
1157  }
1158  BtnPWR.setState(ms, state);
1159  }
1160  }
1161 
1162 #elif defined (CONFIG_IDF_TARGET_ESP32S3)
1163 
1164  switch (_board)
1165  {
1166  case board_t::board_M5AtomS3:
1167  case board_t::board_M5AtomS3Lite:
1168  case board_t::board_M5AtomS3U:
1169  BtnA.setRawState(ms, !m5gfx::gpio_in(GPIO_NUM_41));
1170  break;
1171 
1172  case board_t::board_M5StampS3:
1173  case board_t::board_M5Cardputer:
1174  BtnA.setRawState(ms, !m5gfx::gpio_in(GPIO_NUM_0));
1175  break;
1176 
1177  case board_t::board_M5Capsule:
1178  case board_t::board_M5Dial:
1179  case board_t::board_M5DinMeter:
1180  BtnA.setRawState(ms, !m5gfx::gpio_in(GPIO_NUM_42));
1181  break;
1182 
1183  default:
1184 
1185  if (use_pmic_button)
1186  {
1187  Button_Class::button_state_t state = Button_Class::button_state_t::state_nochange;
1188  bool read_axp = (ms - BtnPWR.getUpdateMsec()) >= BTNPWR_MIN_UPDATE_MSEC;
1189  if (read_axp || BtnPWR.getState())
1190  {
1191  switch (Power.getKeyState())
1192  {
1193  case 0: break;
1194  case 2: state = Button_Class::button_state_t::state_clicked; break;
1195  default: state = Button_Class::button_state_t::state_hold; break;
1196  }
1197  BtnPWR.setState(ms, state);
1198  }
1199  }
1200  break;
1201  }
1202 
1203 #elif defined (CONFIG_IDF_TARGET_ESP32C3)
1204 
1205  switch (_board)
1206  {
1207  case board_t::board_M5StampC3:
1208  BtnA.setRawState(ms, !m5gfx::gpio_in(GPIO_NUM_3));
1209  break;
1210 
1211  case board_t::board_M5StampC3U:
1212  BtnA.setRawState(ms, !m5gfx::gpio_in(GPIO_NUM_9));
1213  break;
1214 
1215  default:
1216  break;
1217  }
1218 
1219 #endif
1220  }
1221 
1222  M5GFX& M5Unified::getDisplay(size_t index)
1223  {
1224  return index != _primary_display_index && index < this->_displays.size() ? this->_displays[index] : Display;
1225  }
1226 
1227  std::size_t M5Unified::addDisplay(M5GFX& dsp)
1228  {
1229  this->_displays.push_back(dsp);
1230  auto res = this->_displays.size() - 1;
1231  setPrimaryDisplay(res == 0 ? 0 : _primary_display_index);
1232 
1233  // Touch screen operation is always limited to the first display.
1234  Touch.begin(_displays.front().touch() ? &_displays.front() : nullptr);
1235 
1236  return res;
1237  }
1238 
1240  int i = 0;
1241  for (auto &d : _displays)
1242  {
1243  if (board == d.getBoard()) { return i; }
1244  ++i;
1245  }
1246  return -1;
1247  }
1248 
1249  int32_t M5Unified::getDisplayIndex(std::initializer_list<m5gfx::board_t> board_list)
1250  {
1251  for (auto b : board_list)
1252  {
1253  int32_t i = getDisplayIndex(b);
1254  if (i >= 0) { return i; }
1255  }
1256  return -1;
1257  }
1258 
1259  bool M5Unified::setPrimaryDisplay(std::size_t index)
1260  {
1261  if (index >= _displays.size()) { return false; }
1262  std::size_t pdi = _primary_display_index;
1263 
1264  if (pdi < _displays.size())
1265  {
1266  _displays[pdi] = Display;
1267  }
1268  _primary_display_index = index;
1269  Display = _displays[index];
1270  return true;
1271  }
1272 
1273  bool M5Unified::setPrimaryDisplayType(std::initializer_list<m5gfx::board_t> board_list)
1274  {
1275  auto i = getDisplayIndex(board_list);
1276  bool res = (i >= 0);
1277  if (res) { setPrimaryDisplay(i); }
1278  return res;
1279  }
1280 
1282  {
1283  Log.setDisplay(getDisplay(index));
1284  }
1285 
1286  void M5Unified::setLogDisplayType(std::initializer_list<m5gfx::board_t> board_list)
1287  {
1288  auto i = getDisplayIndex(board_list);
1289  if (i >= 0) { Log.setDisplay(getDisplay(i)); }
1290  }
1291 }
int16_t value[3]
Definition: IMU_Base.hpp:0
void __attribute((weak)) adc_power_acquire(void)
Definition: M5Unified.cpp:34
m5::M5Unified M5
global instance.
Definition: M5Unified.cpp:32
#define NON_BREAK
[[fallthrough]];
Definition: M5Unified.cpp:28
bool isPressed(void) const
button_state_t getState(void) const
std::uint32_t getUpdateMsec(void) const
void setState(std::uint32_t msec, button_state_t state)
Definition: Button_Class.cpp:8
std::uint32_t getHoldThresh(void) const
void setHoldThresh(std::uint32_t msec)
void setRawState(std::uint32_t msec, bool press)
void setPort(i2c_port_t port_num, int pin_sda, int pin_scl)
Definition: I2C_Class.cpp:13
bool isEnabled(void) const
Definition: I2C_Class.hpp:130
bool writeRegister(std::uint8_t address, std::uint8_t reg, const std::uint8_t *data, std::size_t length, std::uint32_t freq) const
Definition: I2C_Class.cpp:67
bool begin(i2c_port_t port_num, int pin_sda, int pin_scl)
Definition: I2C_Class.cpp:21
bool isEnabled(void) const
Definition: I2C_Class.hpp:192
bool begin(I2C_Class *i2c=nullptr, board_t board=board_t::board_unknown)
Definition: IMU_Class.cpp:28
bool isEnabled(void) const
Definition: IMU_Class.hpp:108
void setDisplay(M5GFX *target)
Definition: Log_Class.cpp:144
Mic_Class Mic
Definition: M5Unified.hpp:233
Button_Class BtnEXT
Definition: M5Unified.hpp:222
bool setPrimaryDisplayType(std::initializer_list< m5gfx::board_t > board_list)
Definition: M5Unified.cpp:1273
void setLogDisplayIndex(size_t index)
Set the display to show logs.
Definition: M5Unified.cpp:1281
Button_Class BtnA
Definition: M5Unified.hpp:219
Button_Class BtnC
Definition: M5Unified.hpp:221
Power_Class Power
Definition: M5Unified.hpp:204
I2C_Class & Ex_I2C
for external I2C device (Port.A)
Definition: M5Unified.hpp:229
Button_Class BtnB
Definition: M5Unified.hpp:220
void setLogDisplayType(std::initializer_list< m5gfx::board_t > board_list)
Definition: M5Unified.cpp:1286
board_t getBoard(void) const
Definition: M5Unified.hpp:297
Button_Class BtnPWR
Definition: M5Unified.hpp:223
std::size_t addDisplay(M5GFX &dsp)
Definition: M5Unified.cpp:1227
M5GFX & getDisplay(size_t index)
Definition: M5Unified.cpp:1222
Touch_Class Touch
Definition: M5Unified.hpp:206
void update(void)
To call this function in a loop function.
Definition: M5Unified.cpp:1056
static void delay(uint32_t msec)
Definition: M5Unified.hpp:276
IMU_Class Imu
Definition: M5Unified.hpp:202
RTC8563_Class Rtc
Definition: M5Unified.hpp:205
Speaker_Class Speaker
Definition: M5Unified.hpp:231
bool setPrimaryDisplay(std::size_t index)
Definition: M5Unified.cpp:1259
static int8_t getPin(pin_name_t name)
Definition: M5Unified.hpp:235
I2C_Class & In_I2C
for internal I2C device
Definition: M5Unified.hpp:226
Log_Class Log
Definition: M5Unified.hpp:203
int32_t getDisplayIndex(m5gfx::board_t board)
Definition: M5Unified.cpp:1239
void setCallback(void *args, bool(*func)(void *, bool))
Definition: Mic_Class.hpp:148
mic_config_t config(void) const
Definition: Mic_Class.hpp:91
void setExtOutput(bool enable, ext_port_mask_t port_mask=(ext_port_mask_t) 0xFF)
bool begin(void)
Definition: Power_Class.cpp:46
void setLed(uint8_t brightness=255)
uint8_t getKeyState(void)
pmic_t getType(void) const
bool begin(I2C_Class *i2c=nullptr)
void setSystemTimeFromRtc(struct timezone *tz=nullptr)
speaker_config_t config(void) const
void setCallback(void *args, bool(*func)(void *, bool))
const touch_detail_t & getDetail(std::size_t index=0) const
Definition: Touch_Class.hpp:91
void begin(m5gfx::LGFX_Device *gfx)
void update(std::uint32_t msec)
Definition: Touch_Class.cpp:8
std::uint8_t getCount(void) const
Definition: Touch_Class.hpp:88
const m5gfx::touch_point_t & getTouchPointRaw(std::size_t index=0) const
Definition: Touch_Class.hpp:94
bool isEnabled(void) const
Definition: M5Unified.cpp:48
@ touch
Definition: Touch_Class.hpp:15
@ mask_moving
Definition: Touch_Class.hpp:34
m5gfx::board_t board_t
Definition: M5Unified.hpp:23
@ in_i2c_sda
Definition: M5Unified.hpp:29
@ sd_spi_sclk
Definition: M5Unified.hpp:40
@ pin_name_max
Definition: M5Unified.hpp:45
@ sd_spi_cipo
Definition: M5Unified.hpp:42
@ ex_i2c_scl
Definition: M5Unified.hpp:30
@ sd_spi_copi
Definition: M5Unified.hpp:41
@ ex_i2c_sda
Definition: M5Unified.hpp:31
@ in_i2c_scl
Definition: M5Unified.hpp:28
struct __attribute__((packed)) rtc_time_t
int pin_data_in
i2s_data_in (for mic)
Definition: Mic_Class.hpp:37
uint8_t over_sampling
Sampling times of obtain the average value.
Definition: Mic_Class.hpp:58
uint32_t sample_rate
input sampling rate (Hz)
Definition: Mic_Class.hpp:49
uint8_t magnification
multiplier for output value