pat9125.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. //pat9125.c
  2. #include "pat9125.h"
  3. #include <util/delay.h>
  4. #include <avr/pgmspace.h>
  5. #include "config.h"
  6. #include <stdio.h>
  7. #include "Configuration_var.h"
  8. #if defined(FILAMENT_SENSOR) && (FILAMENT_SENSOR_TYPE == FSENSOR_PAT9125)
  9. //PAT9125 registers
  10. #define PAT9125_PID1 0x00
  11. #define PAT9125_PID2 0x01
  12. #define PAT9125_MOTION 0x02
  13. #define PAT9125_DELTA_XL 0x03
  14. #define PAT9125_DELTA_YL 0x04
  15. #define PAT9125_MODE 0x05
  16. #define PAT9125_CONFIG 0x06
  17. #define PAT9125_WP 0x09
  18. #define PAT9125_SLEEP1 0x0a
  19. #define PAT9125_SLEEP2 0x0b
  20. #define PAT9125_RES_X 0x0d
  21. #define PAT9125_RES_Y 0x0e
  22. #define PAT9125_DELTA_XYH 0x12
  23. #define PAT9125_SHUTTER 0x14
  24. #define PAT9125_FRAME 0x17
  25. #define PAT9125_ORIENTATION 0x19
  26. #define PAT9125_BANK_SELECTION 0x7f
  27. #if defined(PAT9125_SWI2C)
  28. #include "swi2c.h"
  29. #elif defined(PAT9125_I2C)
  30. #include "twi.h"
  31. #else
  32. #error unknown PAT9125 communication method
  33. #endif
  34. uint8_t pat9125_PID1 = 0;
  35. uint8_t pat9125_PID2 = 0;
  36. int16_t pat9125_x = 0;
  37. int16_t pat9125_y = 0;
  38. uint8_t pat9125_b = 0;
  39. uint8_t pat9125_s = 0;
  40. // Init sequence, address & value.
  41. const PROGMEM uint8_t pat9125_init_bank0[] = {
  42. // Disable write protect.
  43. PAT9125_WP, 0x5a,
  44. // Set the X resolution to zero to let the sensor know that it could safely ignore movement in the X axis.
  45. PAT9125_RES_X, PAT9125_XRES,
  46. // Set the Y resolution to a maximum (or nearly a maximum).
  47. PAT9125_RES_Y, PAT9125_YRES,
  48. // Set data format and sensor orientation.
  49. PAT9125_ORIENTATION, ((PAT9125_12B_RES?0x04:0) | (PAT9125_INVERT_X?0x08:0) | (PAT9125_INVERT_Y?0x10:0) | (PAT9125_SWAP_XY?0x20:0)),
  50. // Now continues the magic sequence from the PAT912EL Application Note: Firmware Guides for Tracking Optimization.
  51. 0x5e, 0x08,
  52. 0x20, 0x64,
  53. 0x2b, 0x6d,
  54. 0x32, 0x2f,
  55. 0xff //end of sequence
  56. };
  57. // Init sequence, address & value.
  58. const PROGMEM uint8_t pat9125_init_bank1[] = {
  59. // Magic sequence to enforce full frame rate of the sensor.
  60. 0x06, 0x028,
  61. 0x33, 0x0d0,
  62. 0x36, 0x0c2,
  63. 0x3e, 0x001,
  64. 0x3f, 0x015,
  65. 0x41, 0x032,
  66. 0x42, 0x03b,
  67. 0x43, 0x0f2,
  68. 0x44, 0x03b,
  69. 0x45, 0x0f2,
  70. 0x46, 0x022,
  71. 0x47, 0x03b,
  72. 0x48, 0x0f2,
  73. 0x49, 0x03b,
  74. 0x4a, 0x0f0,
  75. 0x58, 0x098,
  76. 0x59, 0x00c,
  77. 0x5a, 0x008,
  78. 0x5b, 0x00c,
  79. 0x5c, 0x008,
  80. 0x61, 0x010,
  81. 0x67, 0x09b,
  82. 0x6e, 0x022,
  83. 0x71, 0x007,
  84. 0x72, 0x008,
  85. 0xff //end of sequence
  86. };
  87. static uint8_t pat9125_rd_reg(uint8_t addr);
  88. static void pat9125_wr_reg(uint8_t addr, uint8_t data);
  89. static uint8_t pat9125_wr_reg_verify(uint8_t addr, uint8_t data);
  90. static uint8_t pat9125_wr_seq(const uint8_t* seq);
  91. extern FILE _uartout;
  92. #define uartout (&_uartout)
  93. uint8_t pat9125_probe()
  94. {
  95. #if defined(PAT9125_SWI2C)
  96. swi2c_init();
  97. return swi2c_check(PAT9125_I2C_ADDR) == 0;
  98. #elif defined(PAT9125_I2C)
  99. twi_init();
  100. return twi_check(PAT9125_I2C_ADDR) == 0;
  101. #endif
  102. }
  103. uint8_t pat9125_init(void)
  104. {
  105. if (!pat9125_probe())
  106. return 0;
  107. // Switch to bank0, not allowed to perform pat9125_wr_reg_verify on this register.
  108. pat9125_wr_reg(PAT9125_BANK_SELECTION, 0);
  109. // Verify that the sensor responds with its correct product ID.
  110. pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1);
  111. pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2);
  112. if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91))
  113. {
  114. pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1);
  115. pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2);
  116. if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91))
  117. return 0;
  118. }
  119. #if PAT9125_NEW_INIT
  120. // Software reset (i.e. set bit7 to 1). It will reset to 0 automatically.
  121. // pat9125_wr_reg_verify is not allowed because the register contents will change as soon as they are written. No point in verifying those.
  122. pat9125_wr_reg(PAT9125_CONFIG, 0x97);
  123. // Wait until the sensor reboots.
  124. _delay_ms(1);
  125. //Write init sequence in bank0. MUST ALREADY BE IN bank0.
  126. if (!pat9125_wr_seq(pat9125_init_bank0))
  127. return 0;
  128. _delay_ms(10); // not sure why this is here. But I'll allow it.
  129. // Switch to bank1, not allowed to perform pat9125_wr_reg_verify on this register.
  130. pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x01);
  131. //Write init sequence in bank1. MUST ALREADY BE IN bank1.
  132. if (!pat9125_wr_seq(pat9125_init_bank1))
  133. return 0;
  134. // Switch to bank0, not allowed to perform pat9125_wr_reg_verify on this register.
  135. pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x00);
  136. // Enable write protect.
  137. pat9125_wr_reg(PAT9125_WP, 0x00); //prevents writing to registers over 0x09
  138. pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1);
  139. pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2);
  140. #else //PAT9125_NEW_INIT
  141. // Disable write protect.
  142. pat9125_wr_reg(PAT9125_WP, 0x5a); //allows writing to all registers
  143. pat9125_wr_reg(PAT9125_RES_X, PAT9125_XRES);
  144. pat9125_wr_reg(PAT9125_RES_Y, PAT9125_YRES);
  145. printf_P(PSTR("PAT9125_RES_X=%u\n"), pat9125_rd_reg(PAT9125_RES_X));
  146. printf_P(PSTR("PAT9125_RES_Y=%u\n"), pat9125_rd_reg(PAT9125_RES_Y));
  147. pat9125_wr_reg(PAT9125_ORIENTATION, ((PAT9125_12B_RES?0x04:0) | (PAT9125_INVERT_X?0x08:0) | (PAT9125_INVERT_Y?0x10:0) | (PAT9125_SWAP_XY?0x20:0)));
  148. // Enable write protect.
  149. pat9125_wr_reg(PAT9125_WP, 0x00); //prevents writing to registers over 0x09
  150. #endif //PAT9125_NEW_INIT
  151. return 1;
  152. }
  153. uint8_t pat9125_update(void)
  154. {
  155. if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91))
  156. {
  157. uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION);
  158. pat9125_b = pat9125_rd_reg(PAT9125_FRAME);
  159. pat9125_s = pat9125_rd_reg(PAT9125_SHUTTER);
  160. if (pat9125_PID1 == 0xff) return 0;
  161. if (ucMotion & 0x80)
  162. {
  163. uint16_t ucXL = pat9125_rd_reg(PAT9125_DELTA_XL);
  164. uint16_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL);
  165. uint16_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH);
  166. if (pat9125_PID1 == 0xff) return 0;
  167. int16_t iDX = ucXL | ((ucXYH << 4) & 0xf00);
  168. int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00);
  169. if (iDX & 0x800) iDX -= 4096;
  170. if (iDY & 0x800) iDY -= 4096;
  171. pat9125_x += iDX;
  172. pat9125_y += iDY;
  173. }
  174. return 1;
  175. }
  176. return 0;
  177. }
  178. uint8_t pat9125_update_y(void)
  179. {
  180. if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91))
  181. {
  182. uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION);
  183. if (pat9125_PID1 == 0xff) return 0;
  184. if (ucMotion & 0x80)
  185. {
  186. uint16_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL);
  187. uint16_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH);
  188. if (pat9125_PID1 == 0xff) return 0;
  189. int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00);
  190. if (iDY & 0x800) iDY -= 4096;
  191. pat9125_y += iDY;
  192. }
  193. return 1;
  194. }
  195. return 0;
  196. }
  197. uint8_t pat9125_update_bs(void)
  198. {
  199. if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91))
  200. {
  201. pat9125_b = pat9125_rd_reg(PAT9125_FRAME);
  202. pat9125_s = pat9125_rd_reg(PAT9125_SHUTTER);
  203. if (pat9125_PID1 == 0xff) return 0;
  204. return 1;
  205. }
  206. return 0;
  207. }
  208. static uint8_t pat9125_rd_reg(uint8_t addr)
  209. {
  210. uint8_t data = 0;
  211. #if defined(PAT9125_SWI2C)
  212. if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
  213. goto error;
  214. #elif defined(PAT9125_I2C)
  215. if (twi_r8(PAT9125_I2C_ADDR,addr,&data))
  216. goto error;
  217. #endif
  218. return data;
  219. error:
  220. pat9125_PID1 = 0xff;
  221. pat9125_PID2 = 0xff;
  222. return 0;
  223. }
  224. static void pat9125_wr_reg(uint8_t addr, uint8_t data)
  225. {
  226. #if defined(PAT9125_SWI2C)
  227. if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
  228. goto error;
  229. #elif defined(PAT9125_I2C)
  230. if (twi_w8(PAT9125_I2C_ADDR,addr,data))
  231. goto error;
  232. #endif
  233. return;
  234. error:
  235. pat9125_PID1 = 0xff;
  236. pat9125_PID2 = 0xff;
  237. return;
  238. }
  239. static uint8_t pat9125_wr_reg_verify(uint8_t addr, uint8_t data)
  240. {
  241. pat9125_wr_reg(addr, data);
  242. return pat9125_rd_reg(addr) == data;
  243. }
  244. static uint8_t pat9125_wr_seq(const uint8_t* seq)
  245. {
  246. for (;;) {
  247. const uint8_t addr = pgm_read_byte(seq++);
  248. if (addr == 0xff)
  249. break;
  250. if (!pat9125_wr_reg_verify(addr, pgm_read_byte(seq++)))
  251. // Verification of the register write failed.
  252. return 0;
  253. }
  254. return 1;
  255. }
  256. #endif