diff --git a/FIRMWARE_GPIO_MAP.md b/FIRMWARE_GPIO_MAP.md index d83a9c7..89b041d 100644 --- a/FIRMWARE_GPIO_MAP.md +++ b/FIRMWARE_GPIO_MAP.md @@ -3,14 +3,16 @@ Use este arquivo para documentar os GPIOs do microcontrolador em projetos de firmware. ## Microcontrolador -- Modelo: `` -- Família: `` +- Modelo: `ESP32-C3 (Seeed XIAO ESP32C3)` +- Família: `Espressif ESP32` ## Tabela de GPIOs | GPIO | Direção | Função | Módulo/Periférico | Observações | |---|---|---|---|---| -| `` | `` | `` | `` | `` | +| `D4` | Bidirecional | SDA do barramento de sensores | `I2C/Wire` | Barramento compartilhado entre VL53L0X e QMC6500 | +| `D5` | Saída | SCL do barramento de sensores | `I2C/Wire` | Clock do barramento I2C | +| `D3` | Entrada | Interrupção de vibração do QMC6500 | `GPIO/EXTI` | Configurado com `INPUT_PULLUP`, borda de descida (`FALLING`) | ## Regras diff --git a/architecture/DIAGRAM.md b/architecture/DIAGRAM.md index 1d13a19..e231142 100644 --- a/architecture/DIAGRAM.md +++ b/architecture/DIAGRAM.md @@ -34,6 +34,7 @@ flowchart LR subgraph Driver[Camada de Driver] IR[driver/ir.cpp\nsetup_ir + read_ir] + IMU[driver/imu.cpp\nsetup_imu + imu_has_vibration_event] end subgraph HAL[Camada HAL] @@ -43,27 +44,37 @@ flowchart LR subgraph Host[Execução Host] HMAIN[src/host/main.cpp] MIR[host/mocks/mock_ir.cpp] + MIMU[host/mocks/mock_imu.cpp] MLOG[host/mocks/mock_log.cpp] TESTS[tests/host/unit/*] end subgraph Target[Execução Hardware] TMAIN[src/main.cpp] - SENSOR[VL53L0X] + IRSENSOR[VL53L0X] + IMUSENSOR[QMC6500] UART[Serial] + I2C[Wire] + EXTI[GPIO Interrupt] end APP --> FILTER APP --> IR + APP --> IMU APP --> LOG - IR --> SENSOR + IR --> IRSENSOR + IMU --> IMUSENSOR + IR --> I2C + IMU --> I2C + IMU --> EXTI LOG --> UART HMAIN --> APP TESTS --> APP TESTS --> FILTER TESTS -. substitui .-> MIR + TESTS -. substitui .-> MIMU TESTS -. substitui .-> MLOG TMAIN --> APP diff --git a/architecture/TECHNICAL_BASELINE.md b/architecture/TECHNICAL_BASELINE.md index 847d707..17392c2 100644 --- a/architecture/TECHNICAL_BASELINE.md +++ b/architecture/TECHNICAL_BASELINE.md @@ -9,9 +9,10 @@ mudanças sem conflitar com o fluxo de governança. - `src/app/` - Orquestra o ciclo da aplicação (`setup_app`, `loop_app`). - - Aplica regras de negócio (`half_value`). + - Aplica regras de negócio (`half_value`) e reage a evento de vibração. - `src/driver/` - Integração com sensor IR (VL53L0X). + - Integração com IMU QMC6500 e interrupção por vibração. - `src/hal/` - Inicialização e saída de logs. - `src/host/` @@ -25,6 +26,7 @@ mudanças sem conflitar com o fluxo de governança. - Entrada principal: `src/main.cpp`. - Usa `driver/ir.cpp` real com dependência de biblioteca de sensor. +- Usa `driver/imu.cpp` real com `Wire` e GPIO de interrupção. - Usa `hal/log.cpp` para observabilidade em runtime. ### Host (native) @@ -37,7 +39,8 @@ mudanças sem conflitar com o fluxo de governança. Para preservar testabilidade e baixo acoplamento: -- `driver/ir.h` define contrato de leitura e setup do sensor. +- `driver/ir.h` define contrato de leitura e setup do sensor IR. +- `driver/imu.h` define contrato de setup e consulta de evento de vibração. - `hal/log.h` define contrato de logging. - `app/` depende dos contratos e não de detalhes concretos de hardware. diff --git a/src/app/app.cpp b/src/app/app.cpp index 08429d0..72da086 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -9,11 +9,21 @@ void setup_app() { if (!setup_ir()) { log_info("IR Setup failed"); while(1); - }; + } + + if (!setup_imu()) { + log_info("QMC6500 setup failed"); + while(1); + } } void loop_app() { + if (imu_has_vibration_event()) { + log_info("Vibration event interrupt detected"); + return; + } + uint16_t measure = read_ir(); int half_measure = half_value(measure); log_info("Measure: %d | %d", measure, half_measure); diff --git a/src/app/app.h b/src/app/app.h index 14fb6d0..d6a4e23 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -2,6 +2,7 @@ #include "filter/filter.h" #include "driver/ir.h" +#include "driver/imu.h" void setup_app(); void loop_app(); \ No newline at end of file diff --git a/src/driver/imu.cpp b/src/driver/imu.cpp new file mode 100644 index 0000000..073e250 --- /dev/null +++ b/src/driver/imu.cpp @@ -0,0 +1,74 @@ +#include "imu.h" + +#include +#include + +namespace { +constexpr uint8_t QMC6500_I2C_ADDR = 0x0D; +constexpr uint8_t REG_CTRL1 = 0x09; +constexpr uint8_t REG_CTRL2 = 0x0A; +constexpr uint8_t REG_INT_STATUS = 0x0D; +constexpr uint8_t REG_THRESHOLD = 0x0E; +constexpr uint8_t REG_RESET = 0x0B; +constexpr uint8_t CTRL1_CONTINUOUS_200HZ_2G = 0x1D; +constexpr uint8_t CTRL2_INT_ENABLE = 0x01; +constexpr uint8_t INT_STATUS_VIBRATION = 0x01; +constexpr uint8_t DEFAULT_VIBRATION_THRESHOLD = 0x12; +constexpr uint8_t QMC6500_INT_PIN = D3; + +volatile bool g_vibration_irq = false; + +void write_register(uint8_t reg, uint8_t value) { + Wire.beginTransmission(QMC6500_I2C_ADDR); + Wire.write(reg); + Wire.write(value); + Wire.endTransmission(); +} + +uint8_t read_register(uint8_t reg) { + Wire.beginTransmission(QMC6500_I2C_ADDR); + Wire.write(reg); + if (Wire.endTransmission(false) != 0) { + return 0; + } + + if (Wire.requestFrom(QMC6500_I2C_ADDR, static_cast(1)) != 1) { + return 0; + } + + return Wire.read(); +} + +void IRAM_ATTR on_vibration_interrupt() { + g_vibration_irq = true; +} +} // namespace + +bool setup_imu() { + Wire.begin(); + + write_register(REG_RESET, 0x01); + delay(2); + + write_register(REG_THRESHOLD, DEFAULT_VIBRATION_THRESHOLD); + write_register(REG_CTRL1, CTRL1_CONTINUOUS_200HZ_2G); + write_register(REG_CTRL2, CTRL2_INT_ENABLE); + + pinMode(QMC6500_INT_PIN, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(QMC6500_INT_PIN), on_vibration_interrupt, FALLING); + + return true; +} + +bool imu_has_vibration_event() { + if (!g_vibration_irq) { + return false; + } + + noInterrupts(); + g_vibration_irq = false; + interrupts(); + + const uint8_t status = read_register(REG_INT_STATUS); + return (status & INT_STATUS_VIBRATION) != 0; +} diff --git a/src/driver/imu.h b/src/driver/imu.h new file mode 100644 index 0000000..2e0ab5e --- /dev/null +++ b/src/driver/imu.h @@ -0,0 +1,4 @@ +#pragma once + +bool setup_imu(); +bool imu_has_vibration_event(); diff --git a/src/host/mocks/mock_imu.cpp b/src/host/mocks/mock_imu.cpp new file mode 100644 index 0000000..6ed361f --- /dev/null +++ b/src/host/mocks/mock_imu.cpp @@ -0,0 +1,22 @@ +#include "driver/imu.h" + +static bool mock_setup_imu_output = true; +static bool mock_imu_event = false; + +void set_mock_setup_imu_output(bool output) { + mock_setup_imu_output = output; +} + +void set_mock_imu_event(bool event_raised) { + mock_imu_event = event_raised; +} + +bool setup_imu() { + return mock_setup_imu_output; +} + +bool imu_has_vibration_event() { + bool has_event = mock_imu_event; + mock_imu_event = false; + return has_event; +} diff --git a/src/host/mocks/mock_imu.h b/src/host/mocks/mock_imu.h new file mode 100644 index 0000000..ec1c90e --- /dev/null +++ b/src/host/mocks/mock_imu.h @@ -0,0 +1,4 @@ +#pragma once + +void set_mock_setup_imu_output(bool output); +void set_mock_imu_event(bool event_raised); diff --git a/tests/host/unit/test_loop_app/test_loop_app.cpp b/tests/host/unit/test_loop_app/test_loop_app.cpp index 5b2eb88..6c60b63 100644 --- a/tests/host/unit/test_loop_app/test_loop_app.cpp +++ b/tests/host/unit/test_loop_app/test_loop_app.cpp @@ -2,24 +2,33 @@ #include "app/app.h" #include "host/mocks/mock_log.h" #include "host/mocks/mock_ir.h" - +#include "host/mocks/mock_imu.h" void setUp(void) {} void tearDown(void) {} -void test_loop_app(void) { - uint16_t read_value = 10; - const char* expected = "Measure: 10 | 5"; - set_mock_read_ir_output(read_value); +void test_loop_app_logs_measure_when_no_vibration_event(void) { + set_mock_read_ir_output(10); + set_mock_imu_event(false); + + loop_app(); + + TEST_ASSERT_EQUAL_STRING("Measure: 10 | 5", get_last_log()); +} + +void test_loop_app_logs_vibration_interrupt_when_event_is_raised(void) { + set_mock_read_ir_output(10); + set_mock_imu_event(true); loop_app(); - TEST_ASSERT_EQUAL_STRING(expected, get_last_log()); + TEST_ASSERT_EQUAL_STRING("Vibration event interrupt detected", get_last_log()); } int main(void) { UNITY_BEGIN(); - RUN_TEST(test_loop_app); + RUN_TEST(test_loop_app_logs_measure_when_no_vibration_event); + RUN_TEST(test_loop_app_logs_vibration_interrupt_when_event_is_raised); return UNITY_END(); }