MT6816_ATY.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /**
  2. * @file MT6816_ATY.c
  3. *
  4. * @param Project DEVICE_DRIVER_ATY_LIB
  5. *
  6. * @author ATY
  7. *
  8. * @copyright
  9. * - Copyright 2017 - 2026 MZ-ATY
  10. * - This code follows:
  11. * - MZ-ATY Various Contents Joint Statement -
  12. * <a href="https://mengze.top/MZ-ATY_VCJS">
  13. * https://mengze.top/MZ-ATY_VCJS</a>
  14. * - CC 4.0 BY-NC-SA -
  15. * <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
  16. * https://creativecommons.org/licenses/by-nc-sa/4.0/</a>
  17. * - Your use will be deemed to have accepted the terms of this statement.
  18. *
  19. * @brief functions of MT6816 magnetic encoder for C platform
  20. *
  21. * @note SPI_POLARITY_HIGH + SPI_PHASE_2EDGE = CPOL=1, CPHA=1 = SPI Mode 3
  22. *
  23. * @version
  24. * - 1_01_251222 > ATY
  25. * -# Preliminary version, first Release
  26. ********************************************************************************
  27. */
  28. #ifndef __MT6816_ATY_C
  29. #define __MT6816_ATY_C
  30. #include "MT6816_ATY.h"
  31. #define MT6816_ATY_TAG "\r\n[MT6816_ATY] "
  32. /******************************* For user *************************************/
  33. /******************************************************************************/
  34. uint8_t wrData[3] = {0};
  35. /**
  36. * @brief Parity check
  37. *
  38. * @param dev Device structure pointer
  39. * @param data Data
  40. * @return uint8_t Execution result
  41. */
  42. uint8_t MT6816_ParityCheck(struct MT6816_ATY_Dev* dev, uint16_t data){
  43. uint8_t parityCheck = 0;
  44. if(data == 0) data = dev->angleValue;
  45. dev->error &= ~(uint8_t)MT6816_PARITY_CHECK_MASK;
  46. for(int i = 0; i < 15; i++){
  47. data >>= 1;
  48. if(data & 0x01){
  49. parityCheck ^= 1;
  50. }
  51. }
  52. // Check if parity bit matches (parity bit is bit 7 of angle_lsb)
  53. if((dev->angleValue & 0x01) != parityCheck){
  54. dev->error |= MT6816_PARITY_CHECK_MASK;
  55. printf_ATY_D("%sParity check failed", MT6816_ATY_TAG);
  56. }
  57. return dev->error;
  58. }
  59. /**
  60. * @brief Error check
  61. *
  62. * @param dev Device structure pointer
  63. * @param data Data
  64. * @return uint8_t Execution result
  65. */
  66. uint8_t MT6816_ErrorCheck(struct MT6816_ATY_Dev* dev, uint8_t* data){
  67. dev->error = 0;
  68. MT6816_ParityCheck(dev, (data[0] << 8) | data[1]);
  69. if(data[1] & MT6816_NO_MAG_WARNING_MASK){
  70. dev->error |= MT6816_NO_MAG_WARNING_MASK;
  71. printf_ATY_D("%sNo magnetic field warning", MT6816_ATY_TAG);
  72. }
  73. if(data[2] & MT6816_OVER_SPEED_MASK){
  74. dev->error |= MT6816_OVER_SPEED_MASK;
  75. printf_ATY_D("%sOver speed warning", MT6816_ATY_TAG);
  76. }
  77. return dev->error;
  78. }
  79. /**
  80. * @brief Read angle value from MT6816 for only angle value
  81. *
  82. * @param dev Device structure pointer
  83. * @return uint8_t Execution result
  84. */
  85. uint8_t MT6816_ReadAngleBase(struct MT6816_ATY_Dev* dev){
  86. __ATY_LOCK(dev);
  87. // Reading MSB (ANGLE_MSB register)
  88. wrData[0] = MT6816_REG_ANGLE_13_6 | 0x80;
  89. dev->nssSet(__ATY_HL_L);
  90. dev->spiProcess(wrData, 1, __ATY_RW_W);
  91. dev->spiProcess(wrData, 1, __ATY_RW_R);
  92. dev->nssSet(__ATY_HL_H);
  93. dev->angleValue = ((uint16_t)wrData[0] << 8);
  94. // Reading LSB (ANGLE_LSB register)
  95. wrData[0] = MT6816_REG_ANGLE_5_0 | 0x80;
  96. dev->nssSet(__ATY_HL_L);
  97. dev->spiProcess(wrData, 1, __ATY_RW_W);
  98. dev->spiProcess(wrData, 1, __ATY_RW_R);
  99. dev->nssSet(__ATY_HL_H);
  100. dev->angleValue |= (wrData[0]);
  101. MT6816_ParityCheck(dev, 0);
  102. // dev->angleValue >>= 2;
  103. MT6816_CalculateAngleReal(dev, 0);
  104. __ATY_UNLOCK(dev);
  105. return 0;
  106. }
  107. /**
  108. * @brief Read angle value from MT6816 for all 3 regs
  109. *
  110. * @param dev Device structure pointer
  111. * @return uint8_t Execution result
  112. */
  113. uint8_t MT6816_ReadAngleFull(struct MT6816_ATY_Dev* dev){
  114. __ATY_LOCK(dev);
  115. wrData[0] = MT6816_REG_ANGLE_13_6 | 0x80;
  116. dev->nssSet(__ATY_HL_L);
  117. dev->spiProcess(wrData, 1, __ATY_RW_W);
  118. dev->spiProcess(wrData, 3, __ATY_RW_R);
  119. dev->nssSet(__ATY_HL_H);
  120. // Combine MSB and LSB to form 14-bit angle value
  121. dev->angleValue = ((uint16_t)wrData[0] << 8 | wrData[1]);
  122. MT6816_ErrorCheck(dev, wrData);
  123. // dev->angleValue >>= 2;
  124. MT6816_CalculateAngleReal(dev, 0);
  125. __ATY_UNLOCK(dev);
  126. return 0;
  127. }
  128. /**
  129. * @brief Set zero point
  130. *
  131. * @param dev Device structure pointer
  132. * @return uint8_t Zero point value
  133. */
  134. uint16_t MT6816_SetZeroPoint(struct MT6816_ATY_Dev* dev){
  135. MT6816_ReadAngleFull(dev);
  136. dev->zeroPoint = dev->angleValue >> 2;
  137. return dev->zeroPoint;
  138. }
  139. /**
  140. * @brief Calculate angle in degrees from raw value
  141. *
  142. * @param dev Device structure pointer
  143. * @param angle Raw angle value, if 0, use internal angle value
  144. * @return float Angle in degrees
  145. */
  146. float MT6816_CalculateAngle(struct MT6816_ATY_Dev* dev, uint16_t angle){
  147. if(angle == 0) angle = dev->angleValue >> 2;
  148. dev->angle = (float)angle * 360.0 / 16384.0;
  149. if(dev->angleReverseDir == 1){ dev->angle = 360.0 - dev->angle; }
  150. return dev->angle;
  151. }
  152. /**
  153. * @brief Calculate angle in degrees from raw value and remove zero diff
  154. *
  155. * @param dev Device structure pointer
  156. * @param angle Raw angle value, if 0, use internal angle value
  157. * @return float Angle in degrees
  158. */
  159. float MT6816_CalculateAngleReal(struct MT6816_ATY_Dev* dev, uint16_t angle){
  160. if(angle == 0) angle = dev->angleValue >> 2;
  161. if(angle == dev->zeroPoint) return 0.0;
  162. angle = 16384 + angle - dev->zeroPoint;
  163. if(angle > 16384) angle -= 16384;
  164. return MT6816_CalculateAngle(dev, angle);
  165. }
  166. /**
  167. * @brief Update turn count
  168. *
  169. * @param dev Device structure pointer
  170. * @return uint8_t Execution result
  171. * @note motor fast rpm = 1 / tCycle(sec) / 2 * 60(1min),
  172. * be sure angle can read back every 180 degree.
  173. * only use for increased angle value.
  174. */
  175. uint32_t MT6816_TurnCount(struct MT6816_ATY_Dev* dev){
  176. // jump zero
  177. if(dev->angle - dev->angleLast < -180.0){
  178. dev->turnCount++;
  179. }
  180. dev->angleLast = dev->angle;
  181. return dev->turnCount;
  182. }
  183. uint32_t MT6816_TurnCountOffset(struct MT6816_ATY_Dev* dev){
  184. // jump zero
  185. if(dev->angle - dev->angleLast < -180.0){
  186. dev->angleTotal += dev->angle + 360.0 - dev->angleLast;
  187. }
  188. else{
  189. dev->angleTotal += dev->angle - dev->angleLast;
  190. }
  191. if(dev->angleTotal >= 720.0){
  192. dev->turnCount++;
  193. dev->angleTotal -= 360.0;
  194. }
  195. dev->angleLast = dev->angle;
  196. if(dev->start == 0){
  197. if(dev->angleTotal >= 360.0){
  198. dev->turnCount++;
  199. dev->angleTotal -= 360.0;
  200. }
  201. }
  202. return dev->turnCount;
  203. }
  204. void MT6816_TurnCountOffsetStart(struct MT6816_ATY_Dev* dev, uint8_t dir){
  205. dev->start = 1;
  206. dev->turnCount = 0;
  207. dev->angleStart = dev->angle;
  208. dev->angleLast = dev->angle;
  209. dev->angleTotal = 0;
  210. /* call once TurnCountOffsetStart and TurnCountOffsetStop after change dir,
  211. like:
  212. if(MSSTC_Dev_1.direction != (uint8_t)RGF_MOTOR_DIRECTION){
  213. MSSTC_Dev_1.direction = (uint8_t)RGF_MOTOR_DIRECTION;
  214. MSSTC_Dev_1.dirSet(MSSTC_Dev_1.direction);
  215. MT6816_TurnCountOffsetStart(&MT6816_ATY_Dev_1, MSSTC_Dev_1.direction);
  216. MT6816_TurnCountOffsetStop(&MT6816_ATY_Dev_1);
  217. }
  218. */
  219. dev->angleReverseDir = dir ^ 0x01;
  220. MT6816_TurnCountOffset(dev);
  221. }
  222. void MT6816_TurnCountOffsetStop(struct MT6816_ATY_Dev* dev){
  223. dev->start = 0;
  224. MT6816_TurnCountOffset(dev);
  225. }
  226. #endif /* __MT6816_ATY_C */
  227. /************************************ etc *************************************/
  228. /* init
  229. // MT6816 ---------------------------------------------------------------------
  230. #include "MT6816_ATY.h"
  231. void MT6816_1_NSS_SET(uint8_t level){
  232. if(level == __ATY_HL_L)
  233. HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
  234. else if(level == __ATY_HL_H)
  235. HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);
  236. }
  237. uint8_t MT6816_1_SPI(uint8_t* data_t, uint16_t len, uint8_t rw){
  238. if(rw == __ATY_RW_R){
  239. return HAL_SPI_Receive(&hspi1, (uint8_t*)data_t, len, 1000);
  240. }
  241. else{
  242. return HAL_SPI_Transmit(&hspi1, (uint8_t*)data_t, len, 1000);
  243. }
  244. }
  245. struct MT6816_ATY_Dev MT6816_ATY_Dev_1 = {
  246. .nssSet = MT6816_1_NSS_SET,
  247. .spiProcess = MT6816_1_SPI,
  248. .angleValue = 0,
  249. .angle = 0,
  250. .angleLast = 0,
  251. .angleStart = 0,
  252. .angleTotal = 0,
  253. .turnCount = 0,
  254. .start = 0,
  255. .error = 0,
  256. .zeroPoint = 0,
  257. .angleReverseDir = 1,
  258. .lock = __ATY_UNLOCKED
  259. };
  260. void MT6816_1_Init(void){
  261. MT6816_ReadAngleFull(&MT6816_ATY_Dev_1);
  262. HAL_Delay(100);
  263. MT6816_ReadAngleFull(&MT6816_ATY_Dev_1);
  264. RGF_MOTOR_ANGLE_SET_ZERO = 0;
  265. RGF_MOTOR_ANGLE_ZERO = MT6816_ATY_Dev_1.zeroPoint;
  266. RGF_MOTOR_ANGLE = MT6816_ATY_Dev_1.angle;
  267. RGF_MOTOR_ANGLE_ERR = MT6816_ATY_Dev_1.error;
  268. RGF_MOTOR_ANGLE_ANGLE_START = MT6816_ATY_Dev_1.angleStart;
  269. RGF_MOTOR_ANGLE_TURN_COUNT = MT6816_ATY_Dev_1.turnCount;
  270. RGF_MOTOR_ANGLE_ANGLE_TOTAL = MT6816_ATY_Dev_1.angleTotal;
  271. RGF_MOTOR_ANGLE_START = MT6816_ATY_Dev_1.start;
  272. }
  273. void MT6816_1_UpdateCycle(void){
  274. MT6816_ReadAngleFull(&MT6816_ATY_Dev_1);
  275. MT6816_TurnCountOffset(&MT6816_ATY_Dev_1);
  276. if((uint8_t)RGF_MOTOR_ANGLE_SET_ZERO == 1){
  277. RGF_MOTOR_ANGLE_SET_ZERO = 0;
  278. MT6816_SetZeroPoint(&MT6816_ATY_Dev_1);
  279. }
  280. RGF_MOTOR_ANGLE_ZERO = MT6816_ATY_Dev_1.zeroPoint;
  281. RGF_MOTOR_ANGLE = MT6816_ATY_Dev_1.angle;
  282. RGF_MOTOR_ANGLE_ERR = MT6816_ATY_Dev_1.error;
  283. RGF_MOTOR_ANGLE_ANGLE_START = MT6816_ATY_Dev_1.angleStart;
  284. RGF_MOTOR_ANGLE_TURN_COUNT = MT6816_ATY_Dev_1.turnCount;
  285. RGF_MOTOR_ANGLE_ANGLE_TOTAL = MT6816_ATY_Dev_1.angleTotal;
  286. RGF_MOTOR_ANGLE_START = MT6816_ATY_Dev_1.start;
  287. }
  288. */
  289. /* use
  290. MT6816_1_Init();
  291. // read first value and abort
  292. MT6816_ReadAngleFull(&MT6816_ATY_Dev_1);
  293. HAL_Delay(100);
  294. MT6816_ReadAngleFull(&MT6816_ATY_Dev_1);
  295. // if need to set zero point, read angle value first
  296. MT6816_SetZeroPoint(&MT6816_ATY_Dev_1);
  297. // calculate turn count for motor
  298. MT6816_TurnCountOffset(&MT6816_ATY_Dev_1);
  299. printf_ATY("\r\nAngle: 0x%04X, Degrees: %.2f",
  300. MT6816_ATY_Dev_1.angleValue,
  301. MT6816_ATY_Dev_1.angle);
  302. void MSSTC_1_Cycle(void){
  303. ...
  304. MT6816_1_UpdateCycle();
  305. MSSTC_UpdateAngle(&MSSTC_Dev_1,
  306. MT6816_ATY_Dev_1.turnCount,
  307. MT6816_ATY_Dev_1.angleTotal + MT6816_ATY_Dev_1.angleStart);
  308. if((uint8_t)RGF_MOTOR_RUN == 1){
  309. MT6816_TurnCountOffsetStart(&MT6816_ATY_Dev_1, MSSTC_Dev_1.direction);
  310. MSSTC_Move(&MSSTC_Dev_1, RGF_MOTOR_STEP_COUNT, MT6816_ATY_Dev_1.angleStart);
  311. }
  312. else if((uint8_t)RGF_MOTOR_RUN == 2){
  313. MSSTC_Scram(&MSSTC_Dev_1);
  314. }
  315. RGF_MOTOR_RUN = 0;
  316. if(MSSTC_Dev_1.runState == MSSTC_STATE_STANDBY
  317. && MT6816_ATY_Dev_1.start == 1){
  318. MT6816_TurnCountOffsetStop(&MT6816_ATY_Dev_1);
  319. }
  320. ...
  321. }
  322. */
  323. /******************************************************************************/
  324. /******************************** End Of File *********************************/