Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MyHwSAMD.cpp 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. #include "MyHwSAMD.h"
  20. /*
  21. int8_t pinIntTrigger = 0;
  22. void wakeUp() //place to send the interrupts
  23. {
  24. pinIntTrigger = 1;
  25. }
  26. void wakeUp2() //place to send the second interrupts
  27. {
  28. pinIntTrigger = 2;
  29. }
  30. // Watchdog Timer interrupt service routine. This routine is required
  31. // to allow automatic WDIF and WDIE bit clearance in hardware.
  32. ISR (WDT_vect)
  33. {
  34. // WDIE & WDIF is cleared in hardware upon entering this ISR
  35. wdt_disable();
  36. }
  37. */
  38. void hwReadConfigBlock(void *buf, void *addr, size_t length)
  39. {
  40. uint8_t *dst = static_cast<uint8_t *>(buf);
  41. const int offs = reinterpret_cast<int>(addr);
  42. (void)eep.read(offs, dst, length);
  43. }
  44. void hwWriteConfigBlock(void *buf, void *addr, size_t length)
  45. {
  46. uint8_t *src = static_cast<uint8_t *>(buf);
  47. const int offs = reinterpret_cast<int>(addr);
  48. // use update() instead of write() to reduce e2p wear off
  49. (void)eep.update(offs, src, length);
  50. }
  51. uint8_t hwReadConfig(const int addr)
  52. {
  53. return eep.read(addr);
  54. }
  55. void hwWriteConfig(const int addr, uint8_t value)
  56. {
  57. (void)eep.update(addr, value);
  58. }
  59. bool hwInit(void)
  60. {
  61. #if !defined(MY_DISABLED_SERIAL)
  62. MY_SERIALDEVICE.begin(MY_BAUD_RATE);
  63. #if defined(MY_GATEWAY_SERIAL)
  64. while (!MY_SERIALDEVICE) {}
  65. #endif
  66. #endif
  67. SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN; // Enable the temperature sensor
  68. while (ADC->STATUS.bit.SYNCBUSY ==
  69. 1); // Wait for synchronization of registers between the clock domains
  70. const uint8_t eepInit = eep.begin(MY_EXT_EEPROM_TWI_CLOCK, &Wire);
  71. #if defined(SENSEBENDER_GW_SAMD_V1)
  72. // check connection to external EEPROM - only sensebender GW
  73. return eepInit==0;
  74. #else
  75. (void)eepInit;
  76. return true;
  77. #endif
  78. }
  79. void hwWatchdogReset(void)
  80. {
  81. // TODO: Not supported!
  82. }
  83. void hwReboot(void)
  84. {
  85. NVIC_SystemReset();
  86. while (true);
  87. }
  88. int8_t hwSleep(uint32_t ms)
  89. {
  90. // TODO: Not supported!
  91. (void)ms;
  92. return MY_SLEEP_NOT_POSSIBLE;
  93. }
  94. int8_t hwSleep(uint8_t interrupt, uint8_t mode, uint32_t ms)
  95. {
  96. // TODO: Not supported!
  97. (void)interrupt;
  98. (void)mode;
  99. (void)ms;
  100. return MY_SLEEP_NOT_POSSIBLE;
  101. }
  102. int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
  103. uint32_t ms)
  104. {
  105. // TODO: Not supported!
  106. (void)interrupt1;
  107. (void)mode1;
  108. (void)interrupt2;
  109. (void)mode2;
  110. (void)ms;
  111. return MY_SLEEP_NOT_POSSIBLE;
  112. }
  113. bool hwUniqueID(unique_id_t *uniqueID)
  114. {
  115. (void)memcpy((uint8_t *)uniqueID, (uint32_t *)0x0080A00C, 4);
  116. (void)memcpy((uint8_t *)uniqueID + 4, (uint32_t *)0x0080A040, 12);
  117. return true;
  118. }
  119. // Wait for synchronization of registers between the clock domains
  120. static __inline__ void syncADC() __attribute__((always_inline, unused));
  121. static void syncADC()
  122. {
  123. while (ADC->STATUS.bit.SYNCBUSY);
  124. }
  125. uint16_t hwCPUVoltage(void)
  126. {
  127. // Set ADC reference to internal 1v
  128. ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
  129. ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
  130. syncADC();
  131. // Set to 10 bits reading resolution
  132. ADC->CTRLB.reg = ADC_CTRLB_RESSEL_10BIT | ADC_CTRLB_PRESCALER_DIV256;
  133. syncADC();
  134. // Select MUXPOS as SCALEDIOVCC/4 channel, and MUXNEG as internal ground
  135. ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val;
  136. ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
  137. syncADC();
  138. // enable ADC
  139. ADC->CTRLA.bit.ENABLE = 1;
  140. syncADC();
  141. // start conversion
  142. ADC->SWTRIG.bit.START = 1;
  143. // clear the Data Ready flag
  144. ADC->INTFLAG.bit.RESRDY = 1;
  145. syncADC();
  146. // start conversion again, since The first conversion after the reference is changed must not be used.
  147. ADC->SWTRIG.bit.START = 1;
  148. // waiting for conversion to complete
  149. while (!ADC->INTFLAG.bit.RESRDY);
  150. syncADC();
  151. const uint32_t valueRead = ADC->RESULT.reg;
  152. // disable ADC
  153. ADC->CTRLA.bit.ENABLE = 0;
  154. syncADC();
  155. // value is 1/4 scaled, multiply by 4
  156. return valueRead * 4;
  157. }
  158. uint16_t hwCPUFrequency(void)
  159. {
  160. // TODO: currently reporting compile time frequency (in 1/10MHz)
  161. return F_CPU / 100000UL;
  162. }
  163. int8_t hwCPUTemperature(void)
  164. {
  165. // taken from https://github.com/arduino/ArduinoCore-samd/pull/277
  166. // Set to 12 bits resolution
  167. ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV256;
  168. syncADC();
  169. // Ensure we are sampling slowly
  170. ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x3f);
  171. syncADC();
  172. // Set ADC reference to internal 1v
  173. ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
  174. ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
  175. syncADC();
  176. // Select MUXPOS as temperature channel, and MUXNEG as internal ground
  177. ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_TEMP_Val;
  178. ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
  179. syncADC();
  180. // Enable ADC
  181. ADC->CTRLA.bit.ENABLE = 1;
  182. syncADC();
  183. // Start ADC conversion
  184. ADC->SWTRIG.bit.START = 1;
  185. // Clear the Data Ready flag
  186. ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
  187. syncADC();
  188. // Start conversion again, since The first conversion after the reference is changed must not be used.
  189. ADC->SWTRIG.bit.START = 1;
  190. // Wait until ADC conversion is done
  191. while (!(ADC->INTFLAG.bit.RESRDY));
  192. syncADC();
  193. // Get result
  194. // This is signed so that the math later is done signed
  195. const int32_t adcReading = ADC->RESULT.reg;
  196. // Clear result ready flag
  197. ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
  198. syncADC();
  199. // Disable ADC
  200. ADC->CTRLA.bit.ENABLE = 0;
  201. syncADC();
  202. // Factory room temperature readings
  203. const uint8_t roomInteger = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR &
  204. FUSES_ROOM_TEMP_VAL_INT_Msk)
  205. >> FUSES_ROOM_TEMP_VAL_INT_Pos;
  206. const uint8_t roomDecimal = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR &
  207. FUSES_ROOM_TEMP_VAL_DEC_Msk)
  208. >> FUSES_ROOM_TEMP_VAL_DEC_Pos;
  209. const int32_t roomReading = ((*(uint32_t *)FUSES_ROOM_ADC_VAL_ADDR & FUSES_ROOM_ADC_VAL_Msk) >>
  210. FUSES_ROOM_ADC_VAL_Pos);
  211. const int32_t roomTemperature = 1000 * roomInteger + 100 * roomDecimal;
  212. // Factory hot temperature readings
  213. const uint8_t hotInteger = (*(uint32_t *)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk)
  214. >>
  215. FUSES_HOT_TEMP_VAL_INT_Pos;
  216. const uint8_t hotDecimal = (*(uint32_t *)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk)
  217. >>
  218. FUSES_HOT_TEMP_VAL_DEC_Pos;
  219. const int32_t hotReading = ((*(uint32_t *)FUSES_HOT_ADC_VAL_ADDR & FUSES_HOT_ADC_VAL_Msk) >>
  220. FUSES_HOT_ADC_VAL_Pos);
  221. const int32_t hotTemperature = 1000 * hotInteger + 100 * hotDecimal;
  222. // Linear interpolation of temperature using factory room temperature and hot temperature
  223. const int32_t temperature = roomTemperature + ((hotTemperature - roomTemperature) *
  224. (adcReading - roomReading)) / (hotReading - roomReading);
  225. return static_cast<int8_t>(((temperature / 1000) - MY_SAMD_TEMPERATURE_OFFSET) /
  226. MY_SAMD_TEMPERATURE_GAIN);
  227. }
  228. uint16_t hwFreeMem(void)
  229. {
  230. // TODO: Not supported!
  231. return FUNCTION_NOT_SUPPORTED;
  232. }
  233. void hwDebugPrint(const char *fmt, ... )
  234. {
  235. #ifndef MY_DISABLED_SERIAL
  236. if (MY_DEBUGDEVICE) {
  237. char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
  238. #ifdef MY_GATEWAY_SERIAL
  239. // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
  240. snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%" PRIu8 ";0;%" PRIu8 ";%" PRIu32 " "),
  241. C_INTERNAL, I_LOG_MESSAGE, hwMillis());
  242. MY_DEBUGDEVICE.print(fmtBuffer);
  243. #else
  244. // prepend timestamp
  245. MY_DEBUGDEVICE.print(hwMillis());
  246. MY_DEBUGDEVICE.print(" ");
  247. #endif
  248. va_list args;
  249. va_start(args, fmt);
  250. vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
  251. #ifdef MY_GATEWAY_SERIAL
  252. // Truncate message if this is gateway node
  253. fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
  254. fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
  255. #endif
  256. va_end(args);
  257. MY_DEBUGDEVICE.print(fmtBuffer);
  258. // MY_SERIALDEVICE.flush();
  259. }
  260. #else
  261. (void)fmt;
  262. #endif
  263. }