timer_a.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. MSP430 Emulator
  3. Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)
  4. "MSP430 Emulator" is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. "MSP430 Emulator" is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "timer_a.h"
  16. void handle_timer_a (Emulator *emu)
  17. {
  18. Cpu *cpu = emu->cpu;
  19. Timer_a *timer = cpu->timer_a;
  20. uint16_t TA0CTL = *timer->TA0CTL;
  21. // --------------------------------------------------------------
  22. // Handle Timer_A0 Control Register
  23. uint8_t TASSEL0 = (TA0CTL >> 8) & 0x03;
  24. uint8_t ID0 = (TA0CTL >> 6) & 0x03;
  25. uint8_t MC0 = (TA0CTL >> 4) & 0x03;
  26. uint8_t TA0CLR = (TA0CTL >> 2) & 0x01;
  27. uint8_t TA0IE = (TA0CTL >> 1) & 0x01;
  28. uint8_t TA0IFG = TA0CTL & 0x01;
  29. uint64_t freq = 0;
  30. switch (TASSEL0) {
  31. case 0b00: {timer->source_0 = TACLK; break;}
  32. case 0b01: {timer->source_0 = ACLK; break;}
  33. case 0b10: {timer->source_0 = SMCLK; break;}
  34. case 0b11: {timer->source_0 = INCLK; break;}
  35. default: break;
  36. }
  37. switch (ID0) {
  38. case 0b00: {timer->idiv_0 = 1; break;}
  39. case 0b01: {timer->idiv_0 = 2; break;}
  40. case 0b10: {timer->idiv_0 = 4; break;}
  41. case 0b11: {timer->idiv_0 = 8; break;}
  42. default: break;
  43. }
  44. if(timer->source_0 == ACLK) freq = cpu->bcm->aclk_freq / timer->idiv_0;
  45. else if(timer->source_0 == SMCLK) freq = cpu->bcm->smclk_freq / timer->idiv_0;
  46. switch (MC0) {
  47. case 0b00: {timer->mode_0 = STOP_MODE; break;}
  48. case 0b01: {timer->mode_0 = UP_MODE; break;}
  49. case 0b10: {timer->mode_0 = CONTINOUS_MODE; break;}
  50. case 0b11: {timer->mode_0 = UP_DOWN_MODE; break;}
  51. default: break;
  52. }
  53. /* Timer_A clear; setting this bit resets TAR, the clock divider,
  54. and the count direction. The TACLR bit is automatically
  55. reset and is always read as zero. */
  56. if (TA0CLR) {
  57. *timer->TA0R = 0;
  58. *timer->TA0CTL &= 0xFF0B; // 0b00001011
  59. }
  60. // --------------------------------------------------------------
  61. // --------------------------------------------------------------
  62. // Handle Timer_A0 Capture/Compare Control Register
  63. uint16_t TA0CCTL0 = *timer->TA0CCTL0;
  64. uint16_t TA0CCTL1 = *timer->TA0CCTL1;
  65. uint8_t OUTMOD1 = (TA0CCTL1 >> 5) & 0x07;
  66. uint8_t CCIE = (TA0CCTL0 >> 4) & 0x01;
  67. uint8_t CAP = (TA0CCTL0 >> 8) & 0x01;
  68. // CAP field (Capture or compare mode?)
  69. timer->capture_mode_0 = CAP;
  70. timer->compare_mode_0 = !CAP;
  71. // --------------------------------------------------------------
  72. if(timer->timer_0_running) {
  73. uint64_t period = 1000000000 / freq;
  74. uint64_t value = (cpu->nsecs - timer->timer_0_start) / period;
  75. uint16_t cmp;
  76. if(timer->mode_0 == UP_MODE || timer->mode_0 == CONTINOUS_MODE) {
  77. cmp = (timer->mode_0 == UP_MODE) ? *timer->TA0CCR0 : 0xFFFF;
  78. if(value > cmp) {
  79. value = value % cmp;
  80. timer->timer_0_start = cpu->nsecs;
  81. if(CCIE) service_interrupt(emu, TIMER0_A0_VECTOR);
  82. }
  83. timer->timer_0_freq = (freq * 1.0) / cmp;
  84. }
  85. else if(timer->mode_0 == UP_DOWN_MODE) {
  86. cmp = *timer->TA0CCR0;
  87. if(value > *timer->TA0CCR0 * 2) {
  88. value = value % (*timer->TA0CCR0 * 2);
  89. timer->timer_0_start = cpu->nsecs;
  90. } else if(value > *timer->TA0CCR0) {
  91. if(*timer->TA0R < value && CCIE) service_interrupt(emu, TIMER0_A0_VECTOR);
  92. value = *timer->TA0CCR0 - (value % *timer->TA0CCR0);
  93. }
  94. timer->timer_0_freq = (freq * 2.0) / cmp;
  95. }
  96. switch (OUTMOD1) {
  97. case 0b000: { // 0: Output
  98. timer->timer_0_duty = 0;
  99. break;
  100. }
  101. case 0b001: { // 1: Set
  102. timer->timer_0_duty = (timer->timer_0_duty == 0.0 && value < cmp) ? 0.0 : 1.0;
  103. break;
  104. }
  105. case 0b010: // 2: Toggle/Reset
  106. case 0b011: { // 3: Set/Reset
  107. if(timer->mode_0 == UP_MODE) timer->timer_0_duty = 1.0 - *timer->TA0CCR1 / (double)cmp;
  108. else timer->timer_0_duty = 1.0 - abs(*timer->TA0CCR1 - *timer->TA0CCR0) / (double)cmp;
  109. break;
  110. }
  111. case 0b100: { // 4: Toggle
  112. timer->timer_0_duty = 0.5;
  113. break;
  114. }
  115. case 0b101: { // 5: Reset
  116. timer->timer_0_duty = (timer->timer_0_duty == 1.0 && value < cmp) ? 1.0 : 0.0;
  117. break;
  118. }
  119. case 0b110: // 6: Toggle/Set
  120. case 0b111: { // 7: Reset/Set
  121. double x;
  122. if(timer->mode_0 == UP_MODE) x = *timer->TA0CCR1 / (double)cmp;
  123. else x = abs(*timer->TA0CCR1 - *timer->TA0CCR0) / (double)cmp;
  124. timer->timer_0_duty = x;
  125. break;
  126. }
  127. default: break;
  128. }
  129. *timer->TA0R = (uint16_t)value;
  130. }
  131. /*
  132. static double last_period = 0;
  133. static double last_pulse_width = 0;
  134. // Figure Out Frequency in up mode
  135. if (timer->compare_mode_0) {
  136. if (timer->mode_0 == UP_MODE) {
  137. uint16_t period_ct = *timer->TA0CCR0 + 1;
  138. uint64_t frequency = emu->cpu->bcm->mclk_freq;
  139. double period = (1.0/frequency) * period_ct;// In seconds
  140. double pulse_width = (1.0/frequency) * (*timer->TA0CCR1);
  141. double duty_cycle = pulse_width / period;
  142. // printf("period: %lf\npulse_width: %lf\nduty: %lf%%\n",
  143. // period, pulse_width, duty_cycle);
  144. if (last_period != period || last_pulse_width != pulse_width) {
  145. if (period >= 0.015 && period <= 0.025) { // 0.020 is sweet spot 50 Hz
  146. //printf("period: %lf, last_period: %lf\n", period, last_period);
  147. //printf("pw: %lf, last_pw: %lf\n", pulse_width, last_pulse_width);
  148. if (pulse_width < 0.0009) {
  149. // Send Control for 0 degrees
  150. //print_console(emu, "0 degrres\n");
  151. uint8_t byte = 0;
  152. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  153. }
  154. else if (pulse_width < 0.0012) {
  155. // Send Control for 30 Degrees
  156. //print_console(emu, "30 degrres\n");
  157. uint8_t byte = 30;
  158. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  159. }
  160. else if (pulse_width < 0.0015) {
  161. // Send Control for 60 degrees
  162. uint8_t byte = 60;
  163. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  164. }
  165. else if (pulse_width < 0.0018) {
  166. // Send Control for 90 degrees
  167. //print_console(emu, "90 degrres\n");
  168. uint8_t byte = 90;
  169. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  170. }
  171. else if (pulse_width < 0.0021) {
  172. // Send Control for 120 degrees
  173. uint8_t byte = 120;
  174. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  175. }
  176. else if (pulse_width >= 0.0021) {
  177. // Send Control for 150 degrees
  178. uint8_t byte = 150;
  179. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  180. }
  181. }
  182. }
  183. if (OUTMOD1 == 0b111) { // RESET/SET
  184. uint16_t pulse_width = *timer->TA0CCR1;
  185. }
  186. last_period = period;
  187. last_pulse_width = pulse_width;
  188. }
  189. }
  190. */
  191. if (!timer->timer_0_running && MC0 != 0) {
  192. //print_console(emu, "START TIMER\n");
  193. // puts("TimerA0 started");
  194. timer->timer_0_running = true;
  195. timer->timer_0_start = cpu->nsecs;
  196. //pthread_t pp;
  197. //if(pthread_create(&pp, NULL, timer_A0_thread , (void*)emu)){
  198. //printf("ErrorcreatingDCOthread\n");
  199. //exit(1);
  200. //}
  201. }
  202. if(timer->timer_0_running && MC0 == 0) {
  203. // puts("TimerA0 stopped");
  204. timer->timer_0_running = false;
  205. timer->timer_0_freq = 0;
  206. timer->timer_0_duty = 0;
  207. }
  208. }
  209. void *timer_A0_thread (void *data)
  210. {
  211. Emulator *emu = (Emulator *) data;
  212. Timer_a *timer = emu->cpu->timer_a;
  213. uint64_t counter;
  214. bool high = false;
  215. while (true) {
  216. high = true;
  217. counter = 0;
  218. while (true) {
  219. if ( counter == (*timer->TA0CCR1) ) {
  220. high = false;
  221. }
  222. else if ( counter == (*timer->TA0CCR0 + 1) ) {
  223. break;
  224. }
  225. mclk_wait_cycles(emu, 1);
  226. counter++;
  227. high ? printf("-") : printf("_");
  228. fflush(stdout);
  229. }
  230. }
  231. return NULL;
  232. }
  233. void setup_timer_a (Emulator *emu)
  234. {
  235. Cpu *cpu = emu->cpu;
  236. Timer_a *timer = cpu->timer_a;
  237. // Configure Timer_A0 Registers
  238. const uint16_t TA0CTL_VLOC = 0x160;
  239. const uint16_t TA0R_VLOC = 0x170;
  240. const uint16_t TA0CCTL0_VLOC = 0x162;
  241. const uint16_t TA0CCR0_VLOC = 0x172;
  242. const uint16_t TA0CCTL1_VLOC = 0x164;
  243. const uint16_t TA0CCR1_VLOC = 0x174;
  244. const uint16_t TA0CCTL2_VLOC = 0x166;
  245. const uint16_t TA0CCR2_VLOC = 0x176;
  246. const uint16_t TA0IV_VLOC = 0x12E;
  247. *(timer->TA0CTL = (uint16_t *) get_addr_ptr(TA0CTL_VLOC)) = 0;
  248. *(timer->TA0R = (uint16_t *) get_addr_ptr(TA0R_VLOC)) = 0;
  249. *(timer->TA0CCTL0 = (uint16_t *) get_addr_ptr(TA0CCTL0_VLOC)) = 0;
  250. *(timer->TA0CCR0 = (uint16_t *) get_addr_ptr(TA0CCR0_VLOC)) = 0;
  251. *(timer->TA0CCTL1 = (uint16_t *) get_addr_ptr(TA0CCTL1_VLOC)) = 0;
  252. *(timer->TA0CCR1 = (uint16_t *) get_addr_ptr(TA0CCR1_VLOC)) = 0;
  253. *(timer->TA0CCTL2 = (uint16_t *) get_addr_ptr(TA0CCTL2_VLOC)) = 0;
  254. *(timer->TA0CCR2 = (uint16_t *) get_addr_ptr(TA0CCR2_VLOC)) = 0;
  255. *(timer->TA0IV = (uint16_t *) get_addr_ptr(TA0IV_VLOC)) = 0;
  256. // Configure Timer_A1 Registers
  257. const uint16_t TA1CTL_VLOC = 0x180;
  258. const uint16_t TA1R_VLOC = 0x190;
  259. const uint16_t TA1CCTL0_VLOC = 0x182;
  260. const uint16_t TA1CCR0_VLOC = 0x192;
  261. const uint16_t TA1CCTL1_VLOC = 0x184;
  262. const uint16_t TA1CCR1_VLOC = 0x194;
  263. const uint16_t TA1CCTL2_VLOC = 0x186;
  264. const uint16_t TA1CCR2_VLOC = 0x196;
  265. const uint16_t TA1IV_VLOC = 0x11E;
  266. *(timer->TA1CTL = (uint16_t *) get_addr_ptr(TA1CTL_VLOC)) = 0;
  267. *(timer->TA1R = (uint16_t *) get_addr_ptr(TA1R_VLOC)) = 0;
  268. *(timer->TA1CCTL0 = (uint16_t *) get_addr_ptr(TA1CCTL0_VLOC)) = 0;
  269. *(timer->TA1CCR0 = (uint16_t *) get_addr_ptr(TA1CCR0_VLOC)) = 0;
  270. *(timer->TA1CCTL1 = (uint16_t *) get_addr_ptr(TA1CCTL1_VLOC)) = 0;
  271. *(timer->TA1CCR1 = (uint16_t *) get_addr_ptr(TA1CCR1_VLOC)) = 0;
  272. *(timer->TA1CCTL2 = (uint16_t *) get_addr_ptr(TA1CCTL2_VLOC)) = 0;
  273. *(timer->TA1CCR2 = (uint16_t *) get_addr_ptr(TA1CCR2_VLOC)) = 0;
  274. *(timer->TA1IV = (uint16_t *) get_addr_ptr(TA1IV_VLOC)) = 0;
  275. // Configure other
  276. timer->source_0 = 0b10;
  277. timer->timer_0_running = false;
  278. timer->timer_0_start = 0;
  279. timer->timer_0_freq = 0.0;
  280. timer->timer_0_duty = 0.0;
  281. timer->source_1 = 0b10;
  282. timer->timer_1_running = false;
  283. }
  284. /* POWER UP CLEAR (PUC)
  285. *
  286. * A PUC is always generated when a POR is generated, but a POR is not
  287. * generated by a PUC. The following events trigger a PUC:
  288. *
  289. * A POR signal
  290. * Watchdog timer expiration when in watchdog mode only
  291. * Watchdog timer security key violation
  292. * A Flash memory security key violation
  293. * A CPU instruct fetch from the peripheral address range 0h to 01FFh
  294. void power_up_clear () {
  295. *P1OUT = *P1DIR = *P1IFG = *P1IE = *P1SEL = *P1SEL2 = *P1REN = 0;
  296. }
  297. */