Hiroh Satoh / keyboard Featured

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Fri Aug 26 16:12:28 2016 +0000
Revision:
41:2b034f22b98f
Parent:
40:364deaa190fe
Child:
42:2c3be8694896
fix

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cho45 0:be89b5fdea09 1 /* mbed Microcontroller Library
cho45 0:be89b5fdea09 2 * Copyright (c) 2015 ARM Limited
cho45 0:be89b5fdea09 3 *
cho45 0:be89b5fdea09 4 * Licensed under the Apache License, Version 2.0 (the "License");
cho45 0:be89b5fdea09 5 * you may not use this file except in compliance with the License.
cho45 0:be89b5fdea09 6 * You may obtain a copy of the License at
cho45 0:be89b5fdea09 7 *
cho45 0:be89b5fdea09 8 * http://www.apache.org/licenses/LICENSE-2.0
cho45 0:be89b5fdea09 9 *
cho45 0:be89b5fdea09 10 * Unless required by applicable law or agreed to in writing, software
cho45 0:be89b5fdea09 11 * distributed under the License is distributed on an "AS IS" BASIS,
cho45 0:be89b5fdea09 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cho45 0:be89b5fdea09 13 * See the License for the specific language governing permissions and
cho45 0:be89b5fdea09 14 * limitations under the License.
cho45 0:be89b5fdea09 15 */
cho45 0:be89b5fdea09 16
cho45 30:f9ebc769118d 17 #include <cmath>
cho45 0:be89b5fdea09 18 #include "mbed.h"
cho45 6:f1c3ea8bc850 19
cho45 6:f1c3ea8bc850 20 #include "HIDController_BLE.h"
cho45 6:f1c3ea8bc850 21
cho45 4:54cb552e50c4 22 #include "mcp23017.h"
cho45 5:65d4e94735b6 23 #include "keymap.h"
cho45 0:be89b5fdea09 24
cho45 0:be89b5fdea09 25
cho45 5:65d4e94735b6 26 class KeyboardMatrixController {
cho45 5:65d4e94735b6 27 I2C& i2c;
cho45 5:65d4e94735b6 28 MCP23017 gpio1;
cho45 5:65d4e94735b6 29 MCP23017 gpio2;
cho45 13:b0ffdf2012b9 30 bool gpio1_ready;
cho45 13:b0ffdf2012b9 31 bool gpio2_ready;
cho45 5:65d4e94735b6 32
cho45 5:65d4e94735b6 33 static const uint8_t GPIO1_SLAVE_ADDRESS = 0b0100000;
cho45 14:3a8c126b7834 34 static const uint8_t GPIO2_SLAVE_ADDRESS = 0b0100100;
cho45 5:65d4e94735b6 35
cho45 5:65d4e94735b6 36 /**
cho45 5:65d4e94735b6 37 * COL=GPIOA (output normaly positive)
cho45 5:65d4e94735b6 38 * ROW=GPIOB (input pulled-up)
cho45 5:65d4e94735b6 39 */
cho45 5:65d4e94735b6 40
cho45 13:b0ffdf2012b9 41 bool setupGpio(MCP23017& gpio) {
cho45 5:65d4e94735b6 42 int ok;
cho45 13:b0ffdf2012b9 43 printf("SET IOCON\r\n");
cho45 5:65d4e94735b6 44 ok = gpio.write8(
cho45 5:65d4e94735b6 45 MCP23017::IOCON,
cho45 5:65d4e94735b6 46 0<<MCP23017::BANK |
cho45 5:65d4e94735b6 47 1<<MCP23017::MIRROR |
cho45 5:65d4e94735b6 48 1<<MCP23017::SEQOP |
cho45 5:65d4e94735b6 49 0<<MCP23017::DISSLW |
cho45 5:65d4e94735b6 50 1<<MCP23017::ODR // int pin is open drain
cho45 5:65d4e94735b6 51 );
cho45 13:b0ffdf2012b9 52 if (!ok) return false;
cho45 5:65d4e94735b6 53
cho45 5:65d4e94735b6 54 // IODIR
cho45 5:65d4e94735b6 55 // 1: input
cho45 5:65d4e94735b6 56 // 0: output
cho45 13:b0ffdf2012b9 57 printf("SET IODIRA\r\n");
cho45 5:65d4e94735b6 58 ok = gpio.write16(
cho45 5:65d4e94735b6 59 MCP23017::IODIRA,
cho45 5:65d4e94735b6 60 0b0000000011111111
cho45 5:65d4e94735b6 61 );
cho45 13:b0ffdf2012b9 62 if (!ok) return false;
cho45 4:54cb552e50c4 63
cho45 5:65d4e94735b6 64 // INPUT POLARITY
cho45 5:65d4e94735b6 65 // 1: inverse polarity
cho45 5:65d4e94735b6 66 // 0: raw
cho45 13:b0ffdf2012b9 67 printf("SET IPOLB\r\n");
cho45 5:65d4e94735b6 68 ok = gpio.write8(
cho45 5:65d4e94735b6 69 MCP23017::IPOLB,
cho45 5:65d4e94735b6 70 0b11111111
cho45 5:65d4e94735b6 71 );
cho45 13:b0ffdf2012b9 72 if (!ok) return false;
cho45 5:65d4e94735b6 73
cho45 5:65d4e94735b6 74 // INTERRUPT-ON-CHANGE Enable
cho45 13:b0ffdf2012b9 75 printf("SET GPINTENB\r\n");
cho45 5:65d4e94735b6 76 ok = gpio.write8(
cho45 5:65d4e94735b6 77 MCP23017::GPINTENB,
cho45 5:65d4e94735b6 78 0b11111111
cho45 5:65d4e94735b6 79 );
cho45 13:b0ffdf2012b9 80 if (!ok) return false;
cho45 13:b0ffdf2012b9 81
cho45 5:65d4e94735b6 82 // INTERRUPT-ON-CHANGE Control
cho45 5:65d4e94735b6 83 // 1: compared with DEFVAL
cho45 5:65d4e94735b6 84 // 0: compared to previous value
cho45 13:b0ffdf2012b9 85 printf("SET INTCONB\r\n");
cho45 5:65d4e94735b6 86 ok = gpio.write8(
cho45 5:65d4e94735b6 87 MCP23017::INTCONB,
cho45 5:65d4e94735b6 88 0b00000000
cho45 5:65d4e94735b6 89 );
cho45 13:b0ffdf2012b9 90 if (!ok) return false;
cho45 13:b0ffdf2012b9 91
cho45 5:65d4e94735b6 92 // PULL-UP (for input pin)
cho45 5:65d4e94735b6 93 // 1: pull-up enabled
cho45 5:65d4e94735b6 94 // 0: pull-up disabled
cho45 13:b0ffdf2012b9 95 printf("SET GPPUB\r\n");
cho45 5:65d4e94735b6 96 ok = gpio.write8(
cho45 5:65d4e94735b6 97 MCP23017::GPPUB,
cho45 5:65d4e94735b6 98 0b11111111
cho45 5:65d4e94735b6 99 );
cho45 13:b0ffdf2012b9 100 if (!ok) return false;
cho45 5:65d4e94735b6 101
cho45 13:b0ffdf2012b9 102 printf("SET GPIOA\r\n");
cho45 5:65d4e94735b6 103 ok = gpio1.write8(
cho45 5:65d4e94735b6 104 MCP23017::GPIOA,
cho45 5:65d4e94735b6 105 0b00000000
cho45 5:65d4e94735b6 106 );
cho45 13:b0ffdf2012b9 107 if (!ok) return false;
cho45 5:65d4e94735b6 108
cho45 13:b0ffdf2012b9 109 return true;
cho45 5:65d4e94735b6 110 }
cho45 5:65d4e94735b6 111
cho45 4:54cb552e50c4 112 public:
cho45 5:65d4e94735b6 113 KeyboardMatrixController(I2C& _i2c) :
cho45 5:65d4e94735b6 114 i2c(_i2c),
cho45 5:65d4e94735b6 115 gpio1(i2c, GPIO1_SLAVE_ADDRESS),
cho45 5:65d4e94735b6 116 gpio2(i2c, GPIO2_SLAVE_ADDRESS)
cho45 4:54cb552e50c4 117 {
cho45 4:54cb552e50c4 118 }
cho45 4:54cb552e50c4 119
cho45 5:65d4e94735b6 120 void init() {
cho45 13:b0ffdf2012b9 121 printf("init gpio1\r\n");
cho45 13:b0ffdf2012b9 122 gpio1_ready = setupGpio(gpio1);
cho45 13:b0ffdf2012b9 123 printf("gpio1 initialized: %s\r\n", gpio1_ready ? "success" : "failed");
cho45 13:b0ffdf2012b9 124
cho45 13:b0ffdf2012b9 125 printf("init gpio2\r\n");
cho45 13:b0ffdf2012b9 126 gpio2_ready = setupGpio(gpio2);
cho45 13:b0ffdf2012b9 127 printf("gpio2 initialized: %s\r\n", gpio2_ready ? "success" : "failed");
cho45 13:b0ffdf2012b9 128
cho45 5:65d4e94735b6 129 }
cho45 5:65d4e94735b6 130
cho45 30:f9ebc769118d 131 // __attribute__((used, long_call, section(".data")))
cho45 5:65d4e94735b6 132 void scanKeyboard(uint8_t* keys) {
cho45 5:65d4e94735b6 133 int ok;
cho45 13:b0ffdf2012b9 134
cho45 13:b0ffdf2012b9 135 disableInterrupt();
cho45 5:65d4e94735b6 136
cho45 13:b0ffdf2012b9 137 if (gpio1_ready) {
cho45 13:b0ffdf2012b9 138 for (int i = 0; i < 8; i++) {
cho45 13:b0ffdf2012b9 139 ok = gpio1.write8(
cho45 13:b0ffdf2012b9 140 MCP23017::GPIOA,
cho45 13:b0ffdf2012b9 141 ~(1<<i)
cho45 13:b0ffdf2012b9 142 );
cho45 33:6a2301a89e92 143 wait_us(1);
cho45 13:b0ffdf2012b9 144 keys[i] = gpio1.read8(MCP23017::GPIOB, ok);
cho45 13:b0ffdf2012b9 145 }
cho45 13:b0ffdf2012b9 146
cho45 13:b0ffdf2012b9 147 // set all output to negative for interrupt
cho45 5:65d4e94735b6 148 ok = gpio1.write8(
cho45 5:65d4e94735b6 149 MCP23017::GPIOA,
cho45 13:b0ffdf2012b9 150 0b00000000
cho45 5:65d4e94735b6 151 );
cho45 4:54cb552e50c4 152 }
cho45 2:c2e3f240640c 153
cho45 5:65d4e94735b6 154
cho45 13:b0ffdf2012b9 155 if (gpio2_ready) {
cho45 13:b0ffdf2012b9 156 for (int i = 0; i < 8; i++) {
cho45 13:b0ffdf2012b9 157 ok = gpio2.write8(
cho45 13:b0ffdf2012b9 158 MCP23017::GPIOA,
cho45 13:b0ffdf2012b9 159 ~(1<<i)
cho45 13:b0ffdf2012b9 160 );
cho45 33:6a2301a89e92 161 wait_us(1);
cho45 13:b0ffdf2012b9 162 keys[i+8] = gpio2.read8(MCP23017::GPIOB, ok);
cho45 13:b0ffdf2012b9 163 }
cho45 13:b0ffdf2012b9 164
cho45 13:b0ffdf2012b9 165 // set all output to negative for interrupt
cho45 13:b0ffdf2012b9 166 ok = gpio2.write8(
cho45 13:b0ffdf2012b9 167 MCP23017::GPIOA,
cho45 13:b0ffdf2012b9 168 0b00000000
cho45 13:b0ffdf2012b9 169 );
cho45 13:b0ffdf2012b9 170 }
cho45 13:b0ffdf2012b9 171
cho45 13:b0ffdf2012b9 172 enableInterrupt();
cho45 7:b9270a37345b 173 }
cho45 13:b0ffdf2012b9 174
cho45 38:115875b8cb6c 175 int disableInterrupt() {
cho45 7:b9270a37345b 176 int ok;
cho45 13:b0ffdf2012b9 177 if (gpio1_ready) {
cho45 13:b0ffdf2012b9 178 // Disable interrupt
cho45 13:b0ffdf2012b9 179 ok = gpio1.write8(
cho45 13:b0ffdf2012b9 180 MCP23017::GPINTENB,
cho45 13:b0ffdf2012b9 181 0b00000000
cho45 13:b0ffdf2012b9 182 );
cho45 13:b0ffdf2012b9 183 }
cho45 13:b0ffdf2012b9 184
cho45 13:b0ffdf2012b9 185 if (gpio2_ready) {
cho45 13:b0ffdf2012b9 186 // Disable interrupt
cho45 13:b0ffdf2012b9 187 ok = gpio2.write8(
cho45 13:b0ffdf2012b9 188 MCP23017::GPINTENB,
cho45 13:b0ffdf2012b9 189 0b00000000
cho45 13:b0ffdf2012b9 190 );
cho45 13:b0ffdf2012b9 191 }
cho45 38:115875b8cb6c 192 return ok;
cho45 7:b9270a37345b 193 }
cho45 7:b9270a37345b 194
cho45 38:115875b8cb6c 195 int enableInterrupt() {
cho45 7:b9270a37345b 196 int ok;
cho45 13:b0ffdf2012b9 197 if (gpio1_ready) {
cho45 13:b0ffdf2012b9 198 // Enable interrupt
cho45 13:b0ffdf2012b9 199 ok = gpio1.write8(
cho45 13:b0ffdf2012b9 200 MCP23017::GPINTENB,
cho45 13:b0ffdf2012b9 201 0b11111111
cho45 13:b0ffdf2012b9 202 );
cho45 13:b0ffdf2012b9 203 }
cho45 13:b0ffdf2012b9 204
cho45 13:b0ffdf2012b9 205 if (gpio2_ready) {
cho45 13:b0ffdf2012b9 206 // Enable interrupt
cho45 13:b0ffdf2012b9 207 ok = gpio2.write8(
cho45 13:b0ffdf2012b9 208 MCP23017::GPINTENB,
cho45 13:b0ffdf2012b9 209 0b11111111
cho45 13:b0ffdf2012b9 210 );
cho45 13:b0ffdf2012b9 211 }
cho45 5:65d4e94735b6 212
cho45 5:65d4e94735b6 213 // Clear interrupt
cho45 13:b0ffdf2012b9 214 // gpio1.read8(MCP23017::GPIOB, ok);
cho45 38:115875b8cb6c 215 return ok;
cho45 4:54cb552e50c4 216 }
cho45 5:65d4e94735b6 217 };
cho45 4:54cb552e50c4 218
cho45 5:65d4e94735b6 219 I2C i2c(I2C_SDA0, I2C_SCL0);
cho45 16:345eebc4f259 220 // Serial serial(USBTX, USBRX);
cho45 5:65d4e94735b6 221 KeyboardMatrixController keyboardMatrixController(i2c);
cho45 6:f1c3ea8bc850 222 Keymap keymap;
cho45 15:70bf079d3ee1 223
cho45 15:70bf079d3ee1 224 // Interrupt from MCP23017
cho45 15:70bf079d3ee1 225 // (pulled-up and two MCP23017 is configured with open drain INT)
cho45 5:65d4e94735b6 226 InterruptIn buttonInt(P0_5);
cho45 5:65d4e94735b6 227
cho45 37:4ce71fa47fc3 228 #define PIN_STATUS_LED P0_4
cho45 37:4ce71fa47fc3 229 DigitalOut statusLed(PIN_STATUS_LED, 0);
cho45 25:094df0d9e95b 230
cho45 15:70bf079d3ee1 231 // Unsed pins. Set to output for power consumption
cho45 35:6a7fddfa14cf 232
cho45 35:6a7fddfa14cf 233 // Pad pinout
cho45 35:6a7fddfa14cf 234 /*
cho45 20:d8840ac38434 235 DigitalIn unused_p0_7(P0_7, PullUp);
cho45 20:d8840ac38434 236 DigitalIn unused_p0_6(P0_6, PullUp);
cho45 20:d8840ac38434 237 DigitalIn unused_p0_15(P0_15, PullUp);
cho45 20:d8840ac38434 238 DigitalIn unused_p0_29(P0_29, PullUp);
cho45 20:d8840ac38434 239 DigitalIn unused_p0_28(P0_28, PullUp);
cho45 35:6a7fddfa14cf 240 */
cho45 35:6a7fddfa14cf 241
cho45 20:d8840ac38434 242 DigitalIn unused_p0_19(P0_19, PullUp); // This is on board LED which connected to VDD
cho45 22:a78f0a91280a 243 DigitalIn unused_p0_11(P0_11, PullUp); // RXD
cho45 15:70bf079d3ee1 244
cho45 35:6a7fddfa14cf 245 Timeout timeout;
cho45 35:6a7fddfa14cf 246
cho45 5:65d4e94735b6 247 // ROWS=8
cho45 5:65d4e94735b6 248 // COLS=16
cho45 5:65d4e94735b6 249 // 列ごとに1バイトにパックしてキーの状態を保持する
cho45 5:65d4e94735b6 250 static uint8_t keysA[COLS];
cho45 5:65d4e94735b6 251 static uint8_t keysB[COLS];
cho45 5:65d4e94735b6 252 static bool state = 0;
cho45 28:1f843a3daab0 253 #define is_pressed(keys, row, col) (!!(keys[col] & (1<<row)))
cho45 28:1f843a3daab0 254
cho45 9:d1daefbf1fbd 255 // delay for interrupt
cho45 23:b31957ce64e9 256 static volatile int8_t pollCount = 50;
cho45 5:65d4e94735b6 257
cho45 5:65d4e94735b6 258 void buttonIntCallback() {
cho45 8:d684faf04c9a 259 // just for wakeup
cho45 33:6a2301a89e92 260 pollCount = 25;
cho45 2:c2e3f240640c 261 }
cho45 2:c2e3f240640c 262
cho45 23:b31957ce64e9 263 void powerOff() {
cho45 23:b31957ce64e9 264 printf("power off\r\n");
cho45 23:b31957ce64e9 265 NRF_POWER->SYSTEMOFF = 1;
cho45 23:b31957ce64e9 266 }
cho45 23:b31957ce64e9 267
cho45 26:78ee13f69ec3 268 void tickerStatus() {
cho45 28:1f843a3daab0 269 statusLed = !statusLed;
cho45 26:78ee13f69ec3 270 }
cho45 26:78ee13f69ec3 271
cho45 35:6a7fddfa14cf 272 static bool updateStatudLedEnabled = false;
cho45 35:6a7fddfa14cf 273 void updateStatusLed() {
cho45 35:6a7fddfa14cf 274 switch (HIDController::status()) {
cho45 35:6a7fddfa14cf 275 case TIMEOUT:
cho45 38:115875b8cb6c 276 case DISCONNECTED:
cho45 38:115875b8cb6c 277 case CONNECTED:
cho45 38:115875b8cb6c 278 statusLed = 0;
cho45 38:115875b8cb6c 279 updateStatudLedEnabled = false;
cho45 38:115875b8cb6c 280 return;
cho45 35:6a7fddfa14cf 281 case ADVERTISING:
cho45 38:115875b8cb6c 282 case CONNECTING:
cho45 38:115875b8cb6c 283 statusLed = !statusLed;
cho45 38:115875b8cb6c 284 updateStatudLedEnabled = true;
cho45 38:115875b8cb6c 285 timeout.attach(updateStatusLed, statusLed ? 0.5 : 0.1);
cho45 38:115875b8cb6c 286 break;
cho45 35:6a7fddfa14cf 287 }
cho45 35:6a7fddfa14cf 288 }
cho45 35:6a7fddfa14cf 289
cho45 36:78c211da4eb0 290 static volatile bool keyIntervalInterrupt = false;
cho45 36:78c211da4eb0 291 void wakeupKeyIntervalSleep() {
cho45 36:78c211da4eb0 292 keyIntervalInterrupt = true;
cho45 30:f9ebc769118d 293 }
cho45 30:f9ebc769118d 294
cho45 32:6c0f43fda460 295 class WatchDog {
cho45 32:6c0f43fda460 296 static const uint32_t RELOAD_VALUE = 0x6E524635;
cho45 39:b7889285c9ef 297 static const uint8_t WDT_TIMEOUT = 3; // sec
cho45 32:6c0f43fda460 298 public:
cho45 32:6c0f43fda460 299 static void init() {
cho45 32:6c0f43fda460 300 // timeout [s] = (CRV + 1) / 32768;
cho45 32:6c0f43fda460 301 // crv = 32768 * timeout - 1
cho45 32:6c0f43fda460 302 NRF_WDT->CRV = 32768 * WDT_TIMEOUT - 1;
cho45 32:6c0f43fda460 303 NRF_WDT->RREN = WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos;
cho45 32:6c0f43fda460 304 NRF_WDT->CONFIG = WDT_CONFIG_SLEEP_Pause << WDT_CONFIG_SLEEP_Pos;
cho45 32:6c0f43fda460 305 NRF_WDT->TASKS_START = 1;
cho45 32:6c0f43fda460 306 }
cho45 32:6c0f43fda460 307
cho45 32:6c0f43fda460 308 static void reload() {
cho45 32:6c0f43fda460 309 NRF_WDT->RR[0] = RELOAD_VALUE;
cho45 32:6c0f43fda460 310 }
cho45 35:6a7fddfa14cf 311
cho45 32:6c0f43fda460 312 };
cho45 28:1f843a3daab0 313
cho45 37:4ce71fa47fc3 314 class Battery {
cho45 37:4ce71fa47fc3 315
cho45 37:4ce71fa47fc3 316 public:
cho45 37:4ce71fa47fc3 317 static const float BATTERY_MAX = 2.4;
cho45 37:4ce71fa47fc3 318 static const float REFERNECE = 1.2;
cho45 37:4ce71fa47fc3 319 static const float PRESCALE = 3;
cho45 37:4ce71fa47fc3 320 static const float BATTERY_LOW = 2.0;
cho45 37:4ce71fa47fc3 321
cho45 37:4ce71fa47fc3 322 static uint8_t readBatteryPercentage(float voltage) {
cho45 37:4ce71fa47fc3 323 uint16_t percentage = (voltage - BATTERY_LOW) / (BATTERY_MAX - BATTERY_LOW) * 100;
cho45 37:4ce71fa47fc3 324 if (percentage > 100) percentage = 100;
cho45 37:4ce71fa47fc3 325 return percentage;
cho45 37:4ce71fa47fc3 326 }
cho45 37:4ce71fa47fc3 327
cho45 37:4ce71fa47fc3 328 static float readBatteryVoltage() {
cho45 37:4ce71fa47fc3 329 NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
cho45 37:4ce71fa47fc3 330
cho45 37:4ce71fa47fc3 331 // Use internal 1.2V reference for batteryInput
cho45 37:4ce71fa47fc3 332 // 1/3 pre-scaled input and 1.2V internal band gap reference
cho45 37:4ce71fa47fc3 333 // ref. mbed-src/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/analogin_api.c
cho45 37:4ce71fa47fc3 334 NRF_ADC->CONFIG =
cho45 37:4ce71fa47fc3 335 (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
cho45 37:4ce71fa47fc3 336 // Use VDD 1/3 for input
cho45 37:4ce71fa47fc3 337 (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
cho45 37:4ce71fa47fc3 338 // Use internal band gap for reference
cho45 37:4ce71fa47fc3 339 (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
cho45 37:4ce71fa47fc3 340 (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
cho45 37:4ce71fa47fc3 341
cho45 37:4ce71fa47fc3 342 // Start ADC
cho45 37:4ce71fa47fc3 343 NRF_ADC->TASKS_START = 1;
cho45 37:4ce71fa47fc3 344 while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {
cho45 37:4ce71fa47fc3 345 // busy loop
cho45 37:4ce71fa47fc3 346 }
cho45 37:4ce71fa47fc3 347
cho45 37:4ce71fa47fc3 348 // Read ADC result
cho45 37:4ce71fa47fc3 349 uint16_t raw10bit = static_cast<uint16_t>(NRF_ADC->RESULT);
cho45 37:4ce71fa47fc3 350
cho45 37:4ce71fa47fc3 351 NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled;
cho45 37:4ce71fa47fc3 352
cho45 37:4ce71fa47fc3 353 float ratio = raw10bit / static_cast<float>(1<<10);
cho45 37:4ce71fa47fc3 354
cho45 37:4ce71fa47fc3 355 float batteryVoltage = ratio * (REFERNECE * PRESCALE);
cho45 37:4ce71fa47fc3 356 return batteryVoltage;
cho45 37:4ce71fa47fc3 357 }
cho45 37:4ce71fa47fc3 358 };
cho45 37:4ce71fa47fc3 359
cho45 38:115875b8cb6c 360 #define is_pressed(keys, row, col) (!!(keys[col] & (1<<row)))
cho45 35:6a7fddfa14cf 361
cho45 0:be89b5fdea09 362 int main(void) {
cho45 33:6a2301a89e92 363 {
cho45 33:6a2301a89e92 364 uint32_t reason = NRF_POWER->RESETREAS;
cho45 33:6a2301a89e92 365 NRF_POWER->RESETREAS = 0xffffffff; // clear reason
cho45 33:6a2301a89e92 366 printf("init [%x]\r\n", reason);
cho45 33:6a2301a89e92 367 }
cho45 37:4ce71fa47fc3 368
cho45 37:4ce71fa47fc3 369 float battery = Battery::readBatteryVoltage();
cho45 37:4ce71fa47fc3 370 if (battery < Battery::BATTERY_LOW) {
cho45 37:4ce71fa47fc3 371 powerOff();
cho45 37:4ce71fa47fc3 372 }
cho45 35:6a7fddfa14cf 373
cho45 30:f9ebc769118d 374 // Enable Pin-reset on DEBUG mode
cho45 30:f9ebc769118d 375 // This makes possiable booting without normal mode easily.
cho45 30:f9ebc769118d 376 NRF_POWER->RESET = 1;
cho45 30:f9ebc769118d 377 // Disable Internal DC/DC step down converter surely
cho45 29:ec548c473d50 378 NRF_POWER->DCDCEN = 0;
cho45 30:f9ebc769118d 379 // Enable 2.1V brown out detection for avoiding over discharge of NiMH
cho45 29:ec548c473d50 380 NRF_POWER->POFCON =
cho45 29:ec548c473d50 381 POWER_POFCON_POF_Enabled << POWER_POFCON_POF_Pos |
cho45 29:ec548c473d50 382 POWER_POFCON_THRESHOLD_V21 << POWER_POFCON_THRESHOLD_Pos;
cho45 29:ec548c473d50 383
cho45 4:54cb552e50c4 384 // mbed's Serial of TARGET_RBLAB_BLENANO sucks
cho45 30:f9ebc769118d 385 // DO NOT CONNECT RTS/CTS WITHOUT PRIOR CONSENT!
cho45 4:54cb552e50c4 386 NRF_UART0->PSELRTS = 0xFFFFFFFFUL;
cho45 4:54cb552e50c4 387 NRF_UART0->PSELCTS = 0xFFFFFFFFUL;
cho45 37:4ce71fa47fc3 388
cho45 37:4ce71fa47fc3 389 // Set LED Pin as HIGH Current mode
cho45 37:4ce71fa47fc3 390 NRF_GPIO->PIN_CNF[PIN_STATUS_LED] =
cho45 41:2b034f22b98f 391 (NRF_GPIO->PIN_CNF[PIN_STATUS_LED] & ~GPIO_PIN_CNF_DRIVE_Msk) |
cho45 41:2b034f22b98f 392 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
cho45 16:345eebc4f259 393
cho45 32:6c0f43fda460 394 WatchDog::init();
cho45 31:010a44d53627 395
cho45 4:54cb552e50c4 396 // 100kHz
cho45 36:78c211da4eb0 397 i2c.frequency(250000);
cho45 4:54cb552e50c4 398
cho45 5:65d4e94735b6 399 buttonInt.mode(PullUp);
cho45 5:65d4e94735b6 400 buttonInt.fall(buttonIntCallback);
cho45 4:54cb552e50c4 401
cho45 5:65d4e94735b6 402 keyboardMatrixController.init();
cho45 33:6a2301a89e92 403 pollCount = 10;
cho45 4:54cb552e50c4 404
cho45 6:f1c3ea8bc850 405 HIDController::init();
cho45 16:345eebc4f259 406
cho45 16:345eebc4f259 407 // STOP UART RX for power consumption
cho45 21:d801c32231b0 408 NRF_UART0->TASKS_STOPRX = 1;
cho45 16:345eebc4f259 409
cho45 30:f9ebc769118d 410 // Disable TWI by default.
cho45 16:345eebc4f259 411 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
cho45 35:6a7fddfa14cf 412
cho45 32:6c0f43fda460 413 while (1) {
cho45 32:6c0f43fda460 414 WatchDog::reload();
cho45 35:6a7fddfa14cf 415
cho45 23:b31957ce64e9 416 if (pollCount > 0) {
cho45 23:b31957ce64e9 417 printf("scan keys\r\n");
cho45 31:010a44d53627 418
cho45 33:6a2301a89e92 419 while (pollCount-- > 0) {
cho45 33:6a2301a89e92 420 WatchDog::reload();
cho45 33:6a2301a89e92 421
cho45 23:b31957ce64e9 422 uint8_t (&keysCurr)[COLS] = state ? keysA : keysB;
cho45 23:b31957ce64e9 423 uint8_t (&keysPrev)[COLS] = state ? keysB : keysA;
cho45 23:b31957ce64e9 424
cho45 23:b31957ce64e9 425 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
cho45 23:b31957ce64e9 426 keyboardMatrixController.scanKeyboard(keysCurr);
cho45 23:b31957ce64e9 427 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
cho45 23:b31957ce64e9 428
cho45 23:b31957ce64e9 429 bool queue = false;
cho45 23:b31957ce64e9 430
cho45 23:b31957ce64e9 431 for (int col = 0; col < COLS; col++) {
cho45 23:b31957ce64e9 432 uint8_t changed = keysPrev[col] ^ keysCurr[col];
cho45 23:b31957ce64e9 433 if (changed) queue = true;
cho45 23:b31957ce64e9 434 for (int row = 0; row < ROWS; row++) {
cho45 23:b31957ce64e9 435 if (changed & (1<<row)) {
cho45 23:b31957ce64e9 436 bool pressed = keysCurr[col] & (1<<row);
cho45 23:b31957ce64e9 437 // printf("changed: col=%d, row=%d / pressed=%d\r\n", col, row, pressed);
cho45 23:b31957ce64e9 438 keymap.execute(col, row, pressed);
cho45 23:b31957ce64e9 439 }
cho45 7:b9270a37345b 440 }
cho45 7:b9270a37345b 441 }
cho45 23:b31957ce64e9 442 state = !state;
cho45 35:6a7fddfa14cf 443
cho45 38:115875b8cb6c 444 if (HIDController::status() == DISCONNECTED ||
cho45 38:115875b8cb6c 445 HIDController::status() == TIMEOUT) {
cho45 38:115875b8cb6c 446
cho45 38:115875b8cb6c 447 if (
cho45 38:115875b8cb6c 448 is_pressed(keysCurr, 0, 0) && // left top 1
cho45 38:115875b8cb6c 449 is_pressed(keysCurr, 1, 0) && // left top 2
cho45 38:115875b8cb6c 450 is_pressed(keysCurr, 0, 15) // right top
cho45 38:115875b8cb6c 451 ) {
cho45 38:115875b8cb6c 452 printf("re-init connection\r\n");
cho45 40:364deaa190fe 453 HIDController::initializeConnection(true);
cho45 40:364deaa190fe 454 } else {
cho45 40:364deaa190fe 455 if (HIDController::status() == TIMEOUT) {
cho45 40:364deaa190fe 456 printf("wakeup\r\n");
cho45 40:364deaa190fe 457 HIDController::initializeConnection(false);
cho45 40:364deaa190fe 458 }
cho45 38:115875b8cb6c 459 }
cho45 38:115875b8cb6c 460 }
cho45 35:6a7fddfa14cf 461
cho45 23:b31957ce64e9 462 if (queue) HIDController::queueCurrentReportData();
cho45 30:f9ebc769118d 463
cho45 31:010a44d53627 464 // wait_ms(5); is busy loop
cho45 31:010a44d53627 465 // use timer1 to use wait 5ms
cho45 36:78c211da4eb0 466 timeout.attach_us(wakeupKeyIntervalSleep, 5000);
cho45 36:78c211da4eb0 467 keyIntervalInterrupt = false;
cho45 36:78c211da4eb0 468 while (!keyIntervalInterrupt) sleep();
cho45 7:b9270a37345b 469 }
cho45 8:d684faf04c9a 470 } else {
cho45 35:6a7fddfa14cf 471 if (!updateStatudLedEnabled) updateStatusLed();
cho45 37:4ce71fa47fc3 472
cho45 37:4ce71fa47fc3 473 float batteryVoltage = Battery::readBatteryVoltage();
cho45 37:4ce71fa47fc3 474 uint8_t batteryPercentage = Battery::readBatteryPercentage(batteryVoltage);
cho45 37:4ce71fa47fc3 475 bool isLowBattery = batteryVoltage < Battery::BATTERY_LOW;
cho45 37:4ce71fa47fc3 476
cho45 39:b7889285c9ef 477 printf("%d%% [%d:%s] %s\r\n",
cho45 37:4ce71fa47fc3 478 batteryPercentage,
cho45 37:4ce71fa47fc3 479 HIDController::status(),
cho45 37:4ce71fa47fc3 480 HIDController::statusString(),
cho45 39:b7889285c9ef 481 isLowBattery ? "LOWBAT" : "WFE"
cho45 37:4ce71fa47fc3 482 );
cho45 37:4ce71fa47fc3 483
cho45 37:4ce71fa47fc3 484 HIDController::updateBatteryLevel(batteryPercentage);
cho45 37:4ce71fa47fc3 485
cho45 37:4ce71fa47fc3 486 if (isLowBattery) {
cho45 37:4ce71fa47fc3 487 powerOff();
cho45 37:4ce71fa47fc3 488 }
cho45 29:ec548c473d50 489
cho45 39:b7889285c9ef 490
cho45 39:b7889285c9ef 491 // disable internal HFCLK RC Clock surely. It consume 1mA constantly
cho45 39:b7889285c9ef 492 // TWI / SPI / UART must be disabled and boot without debug mode
cho45 39:b7889285c9ef 493 while (NRF_UART0->EVENTS_TXDRDY != 1);
cho45 39:b7889285c9ef 494
cho45 39:b7889285c9ef 495 uint32_t tx = NRF_UART0->PSELTXD;
cho45 39:b7889285c9ef 496
cho45 39:b7889285c9ef 497 NRF_UART0->TASKS_STOPTX = 1;
cho45 39:b7889285c9ef 498 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos);
cho45 39:b7889285c9ef 499
cho45 39:b7889285c9ef 500 HIDController::waitForEvent();
cho45 39:b7889285c9ef 501
cho45 39:b7889285c9ef 502 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
cho45 39:b7889285c9ef 503 NRF_UART0->TASKS_STARTTX = 1;
cho45 39:b7889285c9ef 504 // dummy send to wakeup...
cho45 39:b7889285c9ef 505 NRF_UART0->PSELTXD = 0xFFFFFFFF;
cho45 39:b7889285c9ef 506 NRF_UART0->EVENTS_TXDRDY = 0;
cho45 39:b7889285c9ef 507 NRF_UART0->TXD = 0;
cho45 39:b7889285c9ef 508 while (NRF_UART0->EVENTS_TXDRDY != 1);
cho45 39:b7889285c9ef 509 NRF_UART0->PSELTXD = tx;
cho45 39:b7889285c9ef 510
cho45 7:b9270a37345b 511 }
cho45 2:c2e3f240640c 512 }
cho45 31:010a44d53627 513 }