NuMaker tickless example

Committer:
ccli8
Date:
Mon Oct 02 11:24:10 2017 +0800
Revision:
10:d2e2c79389e1
Parent:
1:eb1da9d36e12
Child:
16:ed2c228cbc9c
Support NANO130

Who changed what in which revision?

UserRevisionLine numberNew 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 1:eb1da9d36e12 60 int32_t sem_tokens = sem_i2c.wait(osWaitForever);
ccli8 1:eb1da9d36e12 61 if (sem_tokens < 1) {
ccli8 1:eb1da9d36e12 62 continue;
ccli8 1:eb1da9d36e12 63 }
ccli8 1:eb1da9d36e12 64
ccli8 1:eb1da9d36e12 65 bool has_notified_wakeup = false;
ccli8 1:eb1da9d36e12 66 /* This timer is to check if there is I2C traffic remaining. */
ccli8 1:eb1da9d36e12 67 Timer timer;
ccli8 1:eb1da9d36e12 68 timer.start();
ccli8 1:eb1da9d36e12 69
ccli8 1:eb1da9d36e12 70 /* With no I2C traffic for 5 ms, we go back to wait on next I2C traffic. */
ccli8 1:eb1da9d36e12 71 while (timer.read_high_resolution_us() < 5000) {
ccli8 1:eb1da9d36e12 72 /* We shall call I2CSlave::receive to enable I2C interrupt again which may be disabled in handling
ccli8 1:eb1da9d36e12 73 * I2C interrupt in Nuvoton's I2C HAL implementation on mbed OS. */
ccli8 1:eb1da9d36e12 74 int addr_status = i2c_slave.receive();
ccli8 1:eb1da9d36e12 75 switch (addr_status) {
ccli8 1:eb1da9d36e12 76 case I2CSlave::ReadAddressed:
ccli8 1:eb1da9d36e12 77 if (! has_notified_wakeup) {
ccli8 1:eb1da9d36e12 78 has_notified_wakeup = true;
ccli8 1:eb1da9d36e12 79 wakeup_eventflags.set(EventFlag_Wakeup_I2C_AddrMatch);
ccli8 1:eb1da9d36e12 80 }
ccli8 1:eb1da9d36e12 81 i2c_slave.write(i2c_buf, sizeof (i2c_buf));
ccli8 1:eb1da9d36e12 82 timer.reset();
ccli8 1:eb1da9d36e12 83 break;
ccli8 1:eb1da9d36e12 84
ccli8 1:eb1da9d36e12 85 case I2CSlave::WriteAddressed:
ccli8 1:eb1da9d36e12 86 if (! has_notified_wakeup) {
ccli8 1:eb1da9d36e12 87 has_notified_wakeup = true;
ccli8 1:eb1da9d36e12 88 wakeup_eventflags.set(EventFlag_Wakeup_I2C_AddrMatch);
ccli8 1:eb1da9d36e12 89 }
ccli8 1:eb1da9d36e12 90 i2c_slave.read(i2c_buf, sizeof (i2c_buf));
ccli8 1:eb1da9d36e12 91 timer.reset();
ccli8 1:eb1da9d36e12 92 break;
ccli8 1:eb1da9d36e12 93 }
ccli8 1:eb1da9d36e12 94 }
ccli8 1:eb1da9d36e12 95
ccli8 1:eb1da9d36e12 96 /* Clear wake-up events by I2C traffic which would have been handled above */
ccli8 1:eb1da9d36e12 97 sem_i2c.wait(0);
ccli8 1:eb1da9d36e12 98 }
ccli8 1:eb1da9d36e12 99 }
ccli8 1:eb1da9d36e12 100
ccli8 1:eb1da9d36e12 101 void nu_i2c_wakeup_handler(I2C_T *i2c_base)
ccli8 1:eb1da9d36e12 102 {
ccli8 1:eb1da9d36e12 103 (void) i2c_base;
ccli8 1:eb1da9d36e12 104
ccli8 1:eb1da9d36e12 105 sem_i2c.release();
ccli8 1:eb1da9d36e12 106 }