diff --git a/src/M5Unified.cpp b/src/M5Unified.cpp index dd8f1ff..2e1d675 100644 --- a/src/M5Unified.cpp +++ b/src/M5Unified.cpp @@ -98,6 +98,7 @@ static constexpr const uint8_t _pin_table_i2c_ex_in[][5] = { { board_t::board_M5PowerHub , GPIO_NUM_48,GPIO_NUM_45 , GPIO_NUM_16,GPIO_NUM_15 }, { board_t::board_M5StampS3Bat , GPIO_NUM_47,GPIO_NUM_48 , 255 ,255 }, { board_t::board_M5PaperColor , GPIO_NUM_2 ,GPIO_NUM_3 , GPIO_NUM_5 ,GPIO_NUM_4 }, +{ board_t::board_M5ChainCaptain,GPIO_NUM_2 ,GPIO_NUM_3 , GPIO_NUM_6 ,GPIO_NUM_7 }, { board_t::board_M5PaperMono , GPIO_NUM_48,GPIO_NUM_47 , 255 ,255 }, { board_t::board_M5StopWatch , GPIO_NUM_48,GPIO_NUM_47 , GPIO_NUM_11,GPIO_NUM_10 }, { board_t::board_unknown , GPIO_NUM_39,GPIO_NUM_38 , GPIO_NUM_1 ,GPIO_NUM_2 }, // AtomS3,AtomS3Lite,AtomS3U @@ -141,6 +142,7 @@ static constexpr const uint8_t _pin_table_port_bc[][5] = { { board_t::board_M5Dial , GPIO_NUM_1 ,GPIO_NUM_2 , 255 ,255 }, { board_t::board_M5DinMeter , GPIO_NUM_1 ,GPIO_NUM_2 , 255 ,255 }, { board_t::board_M5PowerHub , 255 , 255 , GPIO_NUM_1 ,GPIO_NUM_2 }, +{ board_t::board_M5ChainCaptain,GPIO_NUM_17,GPIO_NUM_18, 255 ,255 }, #elif defined (CONFIG_IDF_TARGET_ESP32C3) #elif defined (CONFIG_IDF_TARGET_ESP32C6) { board_t::board_M5UnitC6L ,GPIO_NUM_4 ,GPIO_NUM_5 , GPIO_NUM_4 ,GPIO_NUM_5 }, @@ -615,6 +617,37 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { return true; } + bool M5Unified::_speaker_enabled_cb_chain_captain(void* args, bool enabled) + { +#if defined (CONFIG_IDF_TARGET_ESP32S3) + auto self = (M5Unified*)args; + static constexpr const uint8_t enabled_bulk_data[] = { + 2, 0x00, 0x80, // 0x00 RESET/ CSM POWER ON + 2, 0x01, 0xB5, // 0x01 CLOCK_MANAGER/ MCLK=BCLK + 2, 0x02, 0x18, // 0x02 CLOCK_MANAGER/ MULT_PRE=3 + 2, 0x0D, 0x01, // 0x0D SYSTEM/ Power up analog circuitry + 2, 0x12, 0x00, // 0x12 SYSTEM/ power-up DAC - NOT default + 2, 0x13, 0x10, // 0x13 SYSTEM/ Enable output to HP drive - NOT default + 2, 0x32, 0xEF, // 0x32 DAC/ DAC volume (0xBF == ±0 dB ) + 2, 0x37, 0x08, // 0x37 DAC/ Bypass DAC equalizer - NOT default + 0 + }; + if (enabled) + { + self->getIOExpander(0).digitalWrite(M5IOE1_Class::gpio5, true); // M5IOE1_G5 audio rail + self->delay(10); + in_i2c_bulk_write(es8311_i2c_addr0, enabled_bulk_data, 100000, 3); + m5gfx::gpio_hi(GPIO_NUM_21); // AW8737A one-wire enable, default mode + } + else + { + m5gfx::gpio_lo(GPIO_NUM_21); + self->getIOExpander(0).digitalWrite(M5IOE1_Class::gpio5, false); + } +#endif + return true; + } + bool M5Unified::_speaker_enabled_cb_tab5(void* args, bool enabled) { (void)args; @@ -1053,6 +1086,37 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { return true; } + bool M5Unified::_microphone_enabled_cb_chain_captain(void* args, bool enabled) + { +#if defined (CONFIG_IDF_TARGET_ESP32S3) + auto self = (M5Unified*)args; + static constexpr const uint8_t enabled_bulk_data[] = { + 2, 0x00, 0x80, // RESET / CSM power on + 2, 0x01, 0xBA, // MCLK from BCLK + 2, 0x02, 0x18, // clock multiplier + 2, 0x0D, 0x01, // power up analog circuitry + 2, 0x0E, 0x02, // enable analog PGA and ADC modulator + 2, 0x14, 0x10, // differential microphone input, minimum PGA gain + 2, 0x17, 0xFF, // ADC volume + 2, 0x1C, 0x6A, // bypass ADC equalizer and cancel DC offset + 0 + }; + static constexpr const uint8_t disabled_bulk_data[] = { + 2, 0x0D, 0xFC, + 2, 0x0E, 0x6A, + 2, 0x00, 0x00, + 0 + }; + if (enabled) + { + self->getIOExpander(0).digitalWrite(M5IOE1_Class::gpio5, true); // M5IOE1_G5 audio rail + self->delay(5); + } + in_i2c_bulk_write(es8311_i2c_addr0, enabled ? enabled_bulk_data : disabled_bulk_data, 100000, 3); +#endif + return true; + } + #if defined (CONFIG_IDF_TARGET_ESP32) && SOC_TOUCH_SENSOR_SUPPORTED static void _read_touch_pad(uint32_t* results, const touch_pad_t* channel, const size_t channel_count) { @@ -1732,6 +1796,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { _io_expander[0].reset(ioexp); } break; + case board_t::board_M5ChainCaptain: case board_t::board_M5PaperMono: case board_t::board_M5StopWatch: { @@ -2001,6 +2066,22 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { m5gfx::pinMode(GPIO_NUM_10, m5gfx::pin_mode_t::input); break; + case board_t::board_M5ChainCaptain: + m5gfx::pinMode(GPIO_NUM_1, m5gfx::pin_mode_t::input); + m5gfx::pinMode(GPIO_NUM_4, m5gfx::pin_mode_t::input); + m5gfx::pinMode(GPIO_NUM_5, m5gfx::pin_mode_t::input); + // Audio PA -- G21 + m5gfx::pinMode(GPIO_NUM_21, m5gfx::pin_mode_t::output); + m5gfx::gpio_lo(GPIO_NUM_21); + // Audio Power -- M5IO1_G5 + { + auto& ioe1 = getIOExpander(0); + ioe1.setHighImpedance(M5IOE1_Class::gpio5, false); + ioe1.setDirection(M5IOE1_Class::gpio5, true); + ioe1.digitalWrite(M5IOE1_Class::gpio5, false); + } + break; + case board_t::board_M5PaperMono: m5gfx::pinMode(GPIO_NUM_2, m5gfx::pin_mode_t::input); m5gfx::pinMode(GPIO_NUM_3, m5gfx::pin_mode_t::input); @@ -2147,6 +2228,19 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { } break; + case board_t::board_M5ChainCaptain: + if (cfg.internal_mic) + { + mic_cfg.pin_mck = GPIO_NUM_40; + mic_cfg.pin_bck = GPIO_NUM_38; + mic_cfg.pin_ws = GPIO_NUM_41; + mic_cfg.pin_data_in = GPIO_NUM_39; + mic_cfg.i2s_port = I2S_NUM_1; + mic_cfg.sample_rate = 16000; + mic_enable_cb = _microphone_enabled_cb_chain_captain; + } + break; + case board_t::board_M5AtomS3U: if (cfg.internal_mic) { @@ -2298,7 +2392,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { spk_cfg.pin_data_out = GPIO_NUM_14; spk_cfg.i2s_port = I2S_NUM_0; spk_cfg.magnification = 1; - spk_cfg.sample_rate = 44100; + spk_cfg.sample_rate = 22050; spk_cfg.stereo = true; spk_cfg.buzzer = false; spk_cfg.use_dac = false; @@ -2476,6 +2570,24 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { } break; + case board_t::board_M5ChainCaptain: + if (cfg.internal_spk) + { + spk_cfg.pin_mck = GPIO_NUM_40; + spk_cfg.pin_bck = GPIO_NUM_38; + spk_cfg.pin_ws = GPIO_NUM_41; + spk_cfg.pin_data_out = GPIO_NUM_42; + spk_cfg.i2s_port = I2S_NUM_0; + spk_cfg.magnification = 1; + spk_cfg.sample_rate = 44100; + spk_cfg.stereo = true; + spk_cfg.buzzer = false; + spk_cfg.use_dac = false; + spk_cfg.dac_zero_level = 0; + spk_enable_cb = _speaker_enabled_cb_chain_captain; + } + break; + case board_t::board_M5Cardputer: case board_t::board_M5CardputerADV: if (cfg.internal_spk) @@ -2937,6 +3049,13 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { | ((!m5gfx::gpio_in(GPIO_NUM_1)) & 1) << 2; break; + case board_t::board_M5ChainCaptain: + use_rawstate_bits = 0b00111; + btn_rawstate_bits = ((!m5gfx::gpio_in(GPIO_NUM_1)) & 1) + | ((!m5gfx::gpio_in(GPIO_NUM_4)) & 1) << 1 + | ((!m5gfx::gpio_in(GPIO_NUM_5)) & 1) << 2; + break; + case board_t::board_M5PaperMono: use_rawstate_bits = 0b00011; btn_rawstate_bits = ((!m5gfx::gpio_in(GPIO_NUM_2)) & 1) diff --git a/src/M5Unified.hpp b/src/M5Unified.hpp index dbacac7..03fa01d 100644 --- a/src/M5Unified.hpp +++ b/src/M5Unified.hpp @@ -660,6 +660,7 @@ namespace m5 static bool _speaker_enabled_cb_sticks3(void* args, bool enabled); static bool _speaker_enabled_cb_papercolor(void* args, bool enabled); static bool _speaker_enabled_cb_stopwatch(void* args, bool enabled); + static bool _speaker_enabled_cb_chain_captain(void* args, bool enabled); static bool _speaker_enabled_cb_tab5(void* args, bool enabled); static bool _speaker_enabled_cb_cardputer_adv(void* args, bool enabled); static bool _speaker_enabled_cb_atom_echos3r(void* args, bool enabled); @@ -670,6 +671,7 @@ namespace m5 static bool _microphone_enabled_cb_sticks3(void* args, bool enabled); static bool _microphone_enabled_cb_papercolor(void* args, bool enabled); static bool _microphone_enabled_cb_stopwatch(void* args, bool enabled); + static bool _microphone_enabled_cb_chain_captain(void* args, bool enabled); static bool _microphone_enabled_cb_tab5(void* args, bool enabled); static bool _microphone_enabled_cb_cardputer_adv(void* args, bool enabled); static bool _microphone_enabled_cb_atomic_echo(void* args, bool enabled); diff --git a/src/utility/IMU_Class.cpp b/src/utility/IMU_Class.cpp index c57d8e5..bb66584 100644 --- a/src/utility/IMU_Class.cpp +++ b/src/utility/IMU_Class.cpp @@ -102,6 +102,12 @@ namespace m5 _internal_axisorder_fixed[sensor_index_accel] = (internal_axisorder_t)(axis_order_yxz | axis_invert_y); _internal_axisorder_fixed[sensor_index_gyro ] = (internal_axisorder_t)(axis_order_yxz | axis_invert_y); _internal_axisorder_fixed[sensor_index_mag ] = (internal_axisorder_t)(axis_invert_x | axis_invert_z); // X軸,Z軸反転 + } else + if (board == m5::board_t::board_M5ChainCaptain) + { // ChainCaptain BMI270 : X=-Y, Y=-X, Z=-Z + _internal_axisorder_fixed[sensor_index_accel] = (internal_axisorder_t)(axis_order_yxz | axis_invert_x | axis_invert_y | axis_invert_z); + _internal_axisorder_fixed[sensor_index_gyro ] = (internal_axisorder_t)(axis_order_yxz | axis_invert_x | axis_invert_y | axis_invert_z); + _internal_axisorder_fixed[sensor_index_mag ] = (internal_axisorder_t)(axis_order_yxz | axis_invert_x | axis_invert_y | axis_invert_z); } #endif diff --git a/src/utility/Power_Class.cpp b/src/utility/Power_Class.cpp index 4be4353..45f971b 100644 --- a/src/utility/Power_Class.cpp +++ b/src/utility/Power_Class.cpp @@ -254,6 +254,30 @@ namespace m5 M5pm1.setGPIODrive(M5PM1_Class::gpio3, M5PM1_Class::push_pull); M5pm1.setGPIOOutput(M5PM1_Class::gpio3, true); // TF card power break; + + case board_t::board_M5ChainCaptain: + _pmic = pmic_t::pmic_m5pm1; + // M5PM1_G0 -- Grove Power + M5pm1.setGPIOFunction(M5PM1_Class::gpio0, M5PM1_Class::gpio); + M5pm1.setGPIOMode(M5PM1_Class::gpio0, M5PM1_Class::output); + M5pm1.setGPIODrive(M5PM1_Class::gpio0, M5PM1_Class::push_pull); + M5pm1.setGPIOOutput(M5PM1_Class::gpio0, false); + // M5PM1_G3 -- Chain Power + M5pm1.setGPIOFunction(M5PM1_Class::gpio3, M5PM1_Class::gpio); + M5pm1.setGPIOMode(M5PM1_Class::gpio3, M5PM1_Class::output); + M5pm1.setGPIODrive(M5PM1_Class::gpio3, M5PM1_Class::push_pull); + M5pm1.setGPIOOutput(M5PM1_Class::gpio3, false); + { + auto& ioe1 = M5.getIOExpander(0); + // M5IOE1_G3 -- Charge Status + ioe1.setDirection(M5IOE1_Class::gpio3, false); + ioe1.enablePull(M5IOE1_Class::gpio3, false); + // M5IOE1_G4 -- Boost Control + ioe1.setHighImpedance(M5IOE1_Class::gpio4, false); + ioe1.setDirection(M5IOE1_Class::gpio4, true); + ioe1.digitalWrite(M5IOE1_Class::gpio4, false); + } + break; case board_t::board_M5PaperMono: _rtcIntPin = GPIO_NUM_1; @@ -682,6 +706,21 @@ namespace m5 } break; + case board_t::board_M5ChainCaptain: + { + if (port_mask & ext_port_mask_t::ext_PA) + { + M5pm1.setGPIOOutput(M5PM1_Class::gpio0, enable); + } + if (port_mask & (ext_port_mask_t::ext_PB1 | ext_port_mask_t::ext_PB2)) + { + M5pm1.setGPIOOutput(M5PM1_Class::gpio3, enable); + } + const bool boost_enabled = M5pm1.getGPIOOutputLatch(M5PM1_Class::gpio0) + || M5pm1.getGPIOOutputLatch(M5PM1_Class::gpio3); + M5.getIOExpander(0).digitalWrite(M5IOE1_Class::gpio4, boost_enabled); + break; + } case board_t::board_M5StampS3Bat: // Use G1 Control 5V output M5pm1.setGPIOOutput(M5PM1_Class::gpio1, enable); @@ -805,6 +844,12 @@ namespace m5 return M5pm1.getExtOutput(); break; + case board_t::board_M5ChainCaptain: + return M5.getIOExpander(0).getWriteValue(M5IOE1_Class::gpio4) + && (M5pm1.getGPIOOutputLatch(M5PM1_Class::gpio0) + || M5pm1.getGPIOOutputLatch(M5PM1_Class::gpio3)); + break; + case board_t::board_M5StampS3Bat: return M5pm1.getGPIOOutputLatch(M5PM1_Class::gpio1); break; @@ -1883,6 +1928,12 @@ namespace m5 } break; + case board_t::board_M5ChainCaptain: + return M5.getIOExpander(0).digitalRead(M5IOE1_Class::gpio3) + ? is_charging_t::is_discharging + : is_charging_t::is_charging; + break; + case board_t::board_M5PaperS3: return (m5gfx::gpio_in(M5PaperS3_CHG_STAT_PIN) == false) ? is_charging_t::is_charging : is_charging_t::is_discharging; @@ -1939,6 +1990,21 @@ namespace m5 return M5pm1.get5VoutVoltage(); } break; + case board_t::board_M5ChainCaptain: { + if (!is_voltage) { return 0; } + static constexpr float diode_offset_mv = 530.0f; + static constexpr float valid_voltage_threshold_mv = 2000.0f; + if (port_mask & ext_port_mask_t::ext_PA) { + float mv = M5pm1.getVBUSVoltage(); + return mv >= valid_voltage_threshold_mv ? mv + diode_offset_mv : mv; + } + if (port_mask & (ext_port_mask_t::ext_PB1 | ext_port_mask_t::ext_PB2)) { + float mv = M5pm1.get5VoutVoltage(); + return mv >= valid_voltage_threshold_mv ? mv + diode_offset_mv : mv; + } + return 0; + } + case board_t::board_M5StampPLC: if (port_mask & (ext_port_mask_t::ext_PWR485 | ext_port_mask_t::ext_PWRCAN)) { if (is_voltage) diff --git a/src/utility/RTC_Class.cpp b/src/utility/RTC_Class.cpp index 11472a9..fbd24f7 100644 --- a/src/utility/RTC_Class.cpp +++ b/src/utility/RTC_Class.cpp @@ -44,6 +44,7 @@ namespace m5 case board_t::board_M5StampPLC: case board_t::board_M5PaperColor: case board_t::board_M5PaperMono: + case board_t::board_M5ChainCaptain: instance.reset(new RX8130_Class(RX8130_Class::DEFAULT_ADDRESS, 400000, i2c)); break; #endif