Nuvoton
/
NuMaker-mbed-tickless-example
NuMaker tickless example
wakeup_i2c.cpp@25:51d3dccddd8b, 21 months ago (annotated)
- Committer:
- cyliang
- Date:
- Wed Mar 01 03:53:04 2023 +0000
- Revision:
- 25:51d3dccddd8b
- Parent:
- 16:ed2c228cbc9c
Update os v6.17.0 for M467 target
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ccli8 |
1:eb1da9d36e12 | 1 | #include "mbed.h" |
ccli8 |
1:eb1da9d36e12 | 2 | #include "wakeup.h" |
ccli8 |
1:eb1da9d36e12 | 3 | #include "PeripheralPins.h" |
ccli8 |
1:eb1da9d36e12 | 4 | |
ccli8 |
1:eb1da9d36e12 | 5 | #define I2C_ADDR (0x90) |
ccli8 |
1:eb1da9d36e12 | 6 | |
ccli8 |
1:eb1da9d36e12 | 7 | #if defined(TARGET_NUMAKER_PFM_NUC472) |
ccli8 |
1:eb1da9d36e12 | 8 | // I2C |
ccli8 |
1:eb1da9d36e12 | 9 | #define I2C_SDA D14 |
ccli8 |
1:eb1da9d36e12 | 10 | #define I2C_SCL D15 |
ccli8 |
1:eb1da9d36e12 | 11 | |
ccli8 |
1:eb1da9d36e12 | 12 | #elif defined(TARGET_NUMAKER_PFM_M453) |
ccli8 |
1:eb1da9d36e12 | 13 | // I2C |
ccli8 |
1:eb1da9d36e12 | 14 | #define I2C_SDA D14 |
ccli8 |
1:eb1da9d36e12 | 15 | #define I2C_SCL D15 |
ccli8 |
1:eb1da9d36e12 | 16 | |
ccli8 |
1:eb1da9d36e12 | 17 | #elif defined(TARGET_NUMAKER_PFM_M487) |
ccli8 |
1:eb1da9d36e12 | 18 | // I2C |
ccli8 |
1:eb1da9d36e12 | 19 | #define I2C_SDA D9 |
ccli8 |
1:eb1da9d36e12 | 20 | #define I2C_SCL D8 |
ccli8 |
1:eb1da9d36e12 | 21 | |
ccli8 |
10:d2e2c79389e1 | 22 | #elif defined(TARGET_NUMAKER_PFM_NANO130) |
ccli8 |
10:d2e2c79389e1 | 23 | // I2C |
ccli8 |
10:d2e2c79389e1 | 24 | #define I2C_SDA D14 |
ccli8 |
10:d2e2c79389e1 | 25 | #define I2C_SCL D15 |
ccli8 |
10:d2e2c79389e1 | 26 | |
ccli8 |
1:eb1da9d36e12 | 27 | #endif |
ccli8 |
1:eb1da9d36e12 | 28 | |
ccli8 |
1:eb1da9d36e12 | 29 | /* NOTE: Per test (on NUC472/M453/M487), we could handle in time from idle mode (shallow sleep) wake-up, |
ccli8 |
1:eb1da9d36e12 | 30 | * but fail from power-down mode (deep sleep). */ |
ccli8 |
1:eb1da9d36e12 | 31 | |
ccli8 |
1:eb1da9d36e12 | 32 | /* Support wake-up by I2C traffic */ |
ccli8 |
1:eb1da9d36e12 | 33 | static Semaphore sem_i2c(0, 1); |
ccli8 |
1:eb1da9d36e12 | 34 | |
ccli8 |
1:eb1da9d36e12 | 35 | static void poll_i2c(void); |
ccli8 |
1:eb1da9d36e12 | 36 | /* This handler is to be called in I2C interrupt context (which is extended by Nuvoton's I2C HAL implementation |
ccli8 |
1:eb1da9d36e12 | 37 | * on mbed OS) to support wake-up by I2C traffic. */ |
ccli8 |
1:eb1da9d36e12 | 38 | extern "C" void nu_i2c_wakeup_handler(I2C_T *i2c_base); |
ccli8 |
1:eb1da9d36e12 | 39 | |
ccli8 |
1:eb1da9d36e12 | 40 | void config_i2c_wakeup(void) |
ccli8 |
1:eb1da9d36e12 | 41 | { |
ccli8 |
1:eb1da9d36e12 | 42 | /* I2C engine is clocked by external I2C bus clock, so its support for wake-up is irrespective of HXT/HIRC |
ccli8 |
1:eb1da9d36e12 | 43 | * which are disabled during deep sleep (power-down). */ |
ccli8 |
1:eb1da9d36e12 | 44 | |
ccli8 |
1:eb1da9d36e12 | 45 | static Thread thread_i2c; |
ccli8 |
1:eb1da9d36e12 | 46 | |
ccli8 |
1:eb1da9d36e12 | 47 | Callback<void()> callback(&poll_i2c); |
ccli8 |
1:eb1da9d36e12 | 48 | thread_i2c.start(callback); |
ccli8 |
1:eb1da9d36e12 | 49 | } |
ccli8 |
1:eb1da9d36e12 | 50 | |
ccli8 |
1:eb1da9d36e12 | 51 | static void poll_i2c(void) |
ccli8 |
1:eb1da9d36e12 | 52 | { |
ccli8 |
1:eb1da9d36e12 | 53 | static I2CSlave i2c_slave(I2C_SDA, I2C_SCL); |
ccli8 |
1:eb1da9d36e12 | 54 | |
ccli8 |
1:eb1da9d36e12 | 55 | static char i2c_buf[32]; |
ccli8 |
1:eb1da9d36e12 | 56 | |
ccli8 |
1:eb1da9d36e12 | 57 | i2c_slave.address(I2C_ADDR); |
ccli8 |
1:eb1da9d36e12 | 58 | |
ccli8 |
1:eb1da9d36e12 | 59 | while (true) { |
ccli8 |
16:ed2c228cbc9c | 60 | sem_i2c.acquire(); |
ccli8 |
16:ed2c228cbc9c | 61 | |
ccli8 |
1:eb1da9d36e12 | 62 | bool has_notified_wakeup = false; |
ccli8 |
1:eb1da9d36e12 | 63 | /* This timer is to check if there is I2C traffic remaining. */ |
ccli8 |
1:eb1da9d36e12 | 64 | Timer timer; |
ccli8 |
1:eb1da9d36e12 | 65 | timer.start(); |
ccli8 |
1:eb1da9d36e12 | 66 | |
ccli8 |
1:eb1da9d36e12 | 67 | /* With no I2C traffic for 5 ms, we go back to wait on next I2C traffic. */ |
ccli8 |
1:eb1da9d36e12 | 68 | while (timer.read_high_resolution_us() < 5000) { |
ccli8 |
1:eb1da9d36e12 | 69 | /* We shall call I2CSlave::receive to enable I2C interrupt again which may be disabled in handling |
ccli8 |
1:eb1da9d36e12 | 70 | * I2C interrupt in Nuvoton's I2C HAL implementation on mbed OS. */ |
ccli8 |
1:eb1da9d36e12 | 71 | int addr_status = i2c_slave.receive(); |
ccli8 |
1:eb1da9d36e12 | 72 | switch (addr_status) { |
ccli8 |
1:eb1da9d36e12 | 73 | case I2CSlave::ReadAddressed: |
ccli8 |
1:eb1da9d36e12 | 74 | if (! has_notified_wakeup) { |
ccli8 |
1:eb1da9d36e12 | 75 | has_notified_wakeup = true; |
ccli8 |
1:eb1da9d36e12 | 76 | wakeup_eventflags.set(EventFlag_Wakeup_I2C_AddrMatch); |
ccli8 |
1:eb1da9d36e12 | 77 | } |
ccli8 |
1:eb1da9d36e12 | 78 | i2c_slave.write(i2c_buf, sizeof (i2c_buf)); |
ccli8 |
1:eb1da9d36e12 | 79 | timer.reset(); |
ccli8 |
1:eb1da9d36e12 | 80 | break; |
ccli8 |
1:eb1da9d36e12 | 81 | |
ccli8 |
1:eb1da9d36e12 | 82 | case I2CSlave::WriteAddressed: |
ccli8 |
1:eb1da9d36e12 | 83 | if (! has_notified_wakeup) { |
ccli8 |
1:eb1da9d36e12 | 84 | has_notified_wakeup = true; |
ccli8 |
1:eb1da9d36e12 | 85 | wakeup_eventflags.set(EventFlag_Wakeup_I2C_AddrMatch); |
ccli8 |
1:eb1da9d36e12 | 86 | } |
ccli8 |
1:eb1da9d36e12 | 87 | i2c_slave.read(i2c_buf, sizeof (i2c_buf)); |
ccli8 |
1:eb1da9d36e12 | 88 | timer.reset(); |
ccli8 |
1:eb1da9d36e12 | 89 | break; |
ccli8 |
1:eb1da9d36e12 | 90 | } |
ccli8 |
1:eb1da9d36e12 | 91 | } |
ccli8 |
1:eb1da9d36e12 | 92 | } |
ccli8 |
1:eb1da9d36e12 | 93 | } |
ccli8 |
1:eb1da9d36e12 | 94 | |
ccli8 |
1:eb1da9d36e12 | 95 | void nu_i2c_wakeup_handler(I2C_T *i2c_base) |
ccli8 |
1:eb1da9d36e12 | 96 | { |
ccli8 |
1:eb1da9d36e12 | 97 | (void) i2c_base; |
ccli8 |
16:ed2c228cbc9c | 98 | |
ccli8 |
16:ed2c228cbc9c | 99 | /* FIXME: Clear wake-up event to enable re-entering Power-down mode */ |
ccli8 |
16:ed2c228cbc9c | 100 | |
ccli8 |
1:eb1da9d36e12 | 101 | sem_i2c.release(); |
ccli8 |
1:eb1da9d36e12 | 102 | } |