티스토리 뷰

HWDesk/HardwareControl

T5838 센서 활용 코드

tothebeyond 2026. 6. 13. 15:49

[Contents]

  • InstrumentManager.cpp
  • BiliMon266Constants.h
  • cSlave_SensorsActuators.h
  • cSlave_SensorsActuators.cpp

 

[InstrumentManager.cpp]

        // 5. T5838 마이크 센서 감지 루틴 (소음 임계값 판단 및 정기 업로드)
        if (localT5838) {
            // AAD 인터럽트 발생 여부 메인 루프에서 감지 및 시리얼 안전 출력
            if (localT5838->checkAndResetAADTrigger()) {
                Serial.println("[T5838 Alert] Acoustic Activity Detected (WAKE pin triggered)!");
            }

            if (currentMillis - lastPollTime_T5838 >= POLL_PERIOD_T5838 || lastPollTime_T5838 == 0) {
                lastPollTime_T5838 = currentMillis;
                float db = localT5838->readNoiseDb();
                if (db >= 0.0f) {
                    bool thresholdBreached = (db >= T5838_DB_THRESHOLD);
                    unsigned long uploadInterval = thresholdBreached ? 1000L : UPLOAD_PERIOD_T5838_NORMAL;
                    
                    static unsigned long lastT5838Upload = 0;
                    if (thresholdBreached || (currentMillis - lastT5838Upload >= uploadInterval || lastT5838Upload == 0)) {
                        lastT5838Upload = currentMillis;
                        cUploadData* micData = new cUploadData();
                        micData->dataType = "T5838";
                        micData->dataName = "SOUND_LEVEL";
                        micData->dataValue1 = "DB:" + String(db, 1);
                        micData->option1 = thresholdBreached ? "AS:110" : "AS:200";
                        micData->option2 = networkManager ? networkManager->getTimeString() : "";
                        micData->isValid = true;
                        
                        if (uploadQueue != NULL) {
                            if (xQueueSend(uploadQueue, &micData, 0) != pdTRUE) {
                                delete micData;
                            }
                        }
                        
                        if (thresholdBreached) {
                            String msg = "🚨 [BiliMon Master Alert] 주변 소음 데시벨(" + String(T5838_DB_THRESHOLD) + "dB)을 초과했습니다! 현재 소음: " + String(db, 1) + " dB";
                            if (networkManager) networkManager->sendInstantAlert(msg);
                        }
                    }
                }
            }
        }

 

[BiliMon266Constants.h]

#define PIN_T5838_CLK              D6         // T5838 I2S PDM CLK (D6)
#define PIN_T5838_DATA             D7         // T5838 I2S PDM DATA (D7)
#define PIN_T5838_WAKE             D8         // T5838 AAD Wakeup 인터럽트 핀
#define PIN_T5838_THSEL            D9         // T5838 1-Wire 설정 핀
#define PIN_T5838_SEL              255

 

[cSlave_SensorsActuators.h]

// ==========================================
// 8. T5838 디지털 PDM/I2S 마이크로폰 모듈
// ==========================================
class cSlave_T5838 {
private:
    uint8_t m_clkPin;
    uint8_t m_dataPin;
    uint8_t m_wakePin;
    uint8_t m_thselPin;
    uint8_t m_selPin;
    bool m_isEnabled;
    int m_i2sPort;
    volatile bool m_aadTriggered; // AAD 발생 감지 플래그

public:
    cSlave_T5838(uint8_t clkPin, uint8_t dataPin, uint8_t wakePin, uint8_t thselPin, uint8_t selPin = 255, int i2sPort = 0);
    bool begin();
    void setEnabled(bool enabled);
    bool isEnabled() const { return m_isEnabled; }
    float readNoiseDb();

    // AAD 인터럽트 처리 및 초기 설정 함수
    void IRAM_ATTR handleWakeInterrupt(); // IRAM 배치 지정
    bool checkAndResetAADTrigger();
    void configureAAD(float thresholdDb);

    // 1-Wire 통신용 함수 (Option A: 스텁 / Option B: 비트뱅잉 로직)
    void writeRegister1Wire(uint8_t regAddr, uint8_t dataVal);
};

 

 

[cSlave_SensorsActuators.cpp]

// ==========================================
// 8. T5838 디지털 PDM/I2S 마이크로폰 모듈
// ==========================================
static cSlave_T5838* g_t5838_instance = nullptr;

void IRAM_ATTR t5838_wake_isr() {
    if (g_t5838_instance) {
        g_t5838_instance->handleWakeInterrupt();
    }
}

cSlave_T5838::cSlave_T5838(uint8_t clkPin, uint8_t dataPin, uint8_t wakePin, uint8_t thselPin, uint8_t selPin, int i2sPort)
    : m_clkPin(clkPin), m_dataPin(dataPin), m_wakePin(wakePin), m_thselPin(thselPin), m_selPin(selPin),
      m_isEnabled(true), m_i2sPort(i2sPort), m_aadTriggered(false) {}

bool cSlave_T5838::begin() {
    if (!m_isEnabled) return false;

    // 1. SEL 핀 설정
    if (m_selPin != 255) {
        pinMode(m_selPin, OUTPUT);
        digitalWrite(m_selPin, LOW); // Left 채널로 구동
    }

    // 2. THSEL 핀 설정 (1-Wire)
    pinMode(m_thselPin, INPUT); // 평상시 Hi-Z 상태 유지

    // 3. WAKE 핀 설정 및 외부 인터럽트 등록 (Option A)
    pinMode(m_wakePin, INPUT_PULLDOWN);
    g_t5838_instance = this;
    attachInterrupt(digitalPinToInterrupt(m_wakePin), t5838_wake_isr, RISING);

    // [Option B - 주석 처리] ESP32 Light Sleep Wakeup Source로 WAKE 핀 등록 코드
    /*
    esp_sleep_enable_ext0_wakeup((gpio_num_t)m_wakePin, 1); // WAKE 핀이 HIGH일 때 Wakeup
    */

    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
        .sample_rate = 16000,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 4,
        .dma_buf_len = 512,
        .use_apll = false,
        .tx_desc_auto_clear = false,
        .fixed_mclk = 0
    };

    i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_PIN_NO_CHANGE,
        .ws_io_num = m_clkPin,
        .data_out_num = I2S_PIN_NO_CHANGE,
        .data_in_num = m_dataPin
    };

    esp_err_t err = i2s_driver_install((i2s_port_t)m_i2sPort, &i2s_config, 0, NULL);
    if (err != ESP_OK) {
        Serial.printf("[T5838] I2S driver install failed: %d\n", err);
        return false;
    }

    err = i2s_set_pin((i2s_port_t)m_i2sPort, &pin_config);
    if (err != ESP_OK) {
        Serial.printf("[T5838] I2S set pin failed: %d\n", err);
        return false;
    }

    Serial.printf("[T5838] PDM Mic initialized on CLK:%d, DATA:%d\n", m_clkPin, m_dataPin);
    return true;
}

void IRAM_ATTR cSlave_T5838::handleWakeInterrupt() {
    m_aadTriggered = true; // ISR 내부이므로 Serial 출력 생략 (Thread-Safe)
}

bool cSlave_T5838::checkAndResetAADTrigger() {
    if (m_aadTriggered) {
        m_aadTriggered = false;
        return true;
    }
    return false;
}

void cSlave_T5838::configureAAD(float thresholdDb) {
    Serial.printf("[T5838] Configuring AAD Threshold to %.1f dB...\n", thresholdDb);
    // Option A: 하드웨어 기본값 사용 (스텁)

    // [Option B - 주석 처리] THSEL을 이용한 실제 레지스터 설정 시나리오 예시
    /*
    // 예시: 0x02 레지스터에 threshold 데이터 작성
    uint8_t rawValue = (uint8_t)(thresholdDb - 40.0f); // T5838에 맞춰 스케일링 가정
    writeRegister1Wire(0x02, rawValue);
    */
}

void cSlave_T5838::writeRegister1Wire(uint8_t regAddr, uint8_t dataVal) {
    // [Option B - 주석 처리] PDM CLK를 이용한 1-Wire 비트뱅잉 타이밍 전송 예시 코드
    /*
    pinMode(m_thselPin, OUTPUT);
    // 1-Wire 프로토콜에 따라 시작 조건, 레지스터 주소 비트, 데이터 비트 모듈레이션
    // 각 비트는 CLK의 엣지에 동기화하여 전송합니다.
    // ...
    pinMode(m_thselPin, INPUT); // 완료 후 Hi-Z 복귀
    */
}

void cSlave_T5838::setEnabled(bool enabled) {
    m_isEnabled = enabled;
    if (!m_isEnabled) {
        i2s_stop((i2s_port_t)m_i2sPort);
    } else {
        i2s_start((i2s_port_t)m_i2sPort);
    }
}

float cSlave_T5838::readNoiseDb() {
    if (!m_isEnabled) return -999.0f;

    int16_t samples[512];
    size_t bytesRead = 0;
    esp_err_t err = i2s_read((i2s_port_t)m_i2sPort, (void*)samples, sizeof(samples), &bytesRead, pdMS_TO_TICKS(50));
    if (err != ESP_OK || bytesRead == 0) {
        return -999.0f;
    }

    int sampleCount = bytesRead / sizeof(int16_t);
    double sum = 0;
    for (int i = 0; i < sampleCount; i++) {
        sum += (double)samples[i] * samples[i];
    }

    if (sampleCount == 0) return 0.0f;

    double rms = sqrt(sum / sampleCount);
    float db = 20.0f * log10(rms + 1.0);
    return db;
}

 

 

 

 

 

반응형
반응형
250x250
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함