timer_a.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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. switch (OUTMOD1) {
  85. case 0b000: { // 0: Output
  86. timer->timer_0_duty = 0;
  87. break;
  88. }
  89. case 0b001: { // 1: Set
  90. timer->timer_0_duty = (timer->timer_0_duty == 0.0 && value < cmp) ? 0.0 : 1.0;
  91. break;
  92. }
  93. case 0b010: // 2: Toggle/Reset
  94. case 0b011: { // 3: Set/Reset
  95. if(timer->mode_0 == UP_MODE)
  96. timer->timer_0_duty = 1.0 - *timer->TA0CCR1 / (double)cmp;
  97. else timer->timer_0_duty = 1.0 - abs(*timer->TA0CCR0 - *timer->TA0CCR1) / (double)cmp;
  98. break;
  99. }
  100. case 0b100: { // 4: Toggle
  101. timer->timer_0_duty = 0.5;
  102. break;
  103. }
  104. case 0b101: { // 5: Reset
  105. timer->timer_0_duty = (timer->timer_0_duty == 1.0 && value < cmp) ? 1.0 : 0.0;
  106. break;
  107. }
  108. case 0b110: // 6: Toggle/Set
  109. case 0b111: { // 7: Reset/Set
  110. if(timer->mode_0 == UP_MODE) timer->timer_0_duty = *timer->TA0CCR1 / (double)cmp;
  111. else timer->timer_0_duty = abs(*timer->TA0CCR0 - *timer->TA0CCR1) / (double)cmp;
  112. break;
  113. }
  114. default: break;
  115. }
  116. }
  117. else if(timer->mode_0 == UP_DOWN_MODE) {
  118. cmp = *timer->TA0CCR0;
  119. if(value > *timer->TA0CCR0 * 2) {
  120. value = value % (*timer->TA0CCR0 * 2);
  121. timer->timer_0_start = cpu->nsecs;
  122. } else if(value > *timer->TA0CCR0) {
  123. if(*timer->TA0R < value && CCIE) service_interrupt(emu, TIMER0_A0_VECTOR);
  124. value = *timer->TA0CCR0 - (value % *timer->TA0CCR0);
  125. }
  126. timer->timer_0_freq = (freq * 2.0) / cmp;
  127. switch (OUTMOD1) {
  128. case 0b000: { // 0: Output
  129. timer->timer_0_duty = 0;
  130. break;
  131. }
  132. case 0b001: { // 1: Set
  133. timer->timer_0_duty = (timer->timer_0_duty == 0.0 && value < cmp) ? 0.0 : 1.0;
  134. break;
  135. }
  136. case 0b101: { // 5: Reset
  137. timer->timer_0_duty = (timer->timer_0_duty == 1.0 && value < cmp) ? 1.0 : 0.0;
  138. break;
  139. }
  140. case 0b010: { // 2: Toggle/Reset
  141. if(*timer->TA0CCR2 >= *timer->TA0CCR0) timer->timer_0_duty = 1.0;
  142. else timer->timer_0_duty = 1.0 - 2 * (*timer->TA0CCR0 - *timer->TA0CCR2) / (double)cmp;
  143. break;
  144. }
  145. case 0b011: { // 3: Set/Reset
  146. if(*timer->TA0CCR2 >= *timer->TA0CCR0) timer->timer_0_duty = 1.0;
  147. else timer->timer_0_duty = 1.0 - (*timer->TA0CCR0 - *timer->TA0CCR2) / (double)cmp;
  148. break;
  149. }
  150. // TODO: in toggle mode this can be this or 1.0 - duty depending on initial state
  151. case 0b100: // 4: Toggle
  152. case 0b110: { // 6: Toggle/Set
  153. if(*timer->TA0CCR2 >= *timer->TA0CCR0) timer->timer_0_duty = 0.0;
  154. else timer->timer_0_duty = 2 * (*timer->TA0CCR0 - *timer->TA0CCR2) / (double)cmp;
  155. break;
  156. }
  157. case 0b111: { // 7: Reset/Set
  158. if(*timer->TA0CCR2 >= *timer->TA0CCR0) timer->timer_0_duty = 0.0;
  159. else timer->timer_0_duty = (*timer->TA0CCR0 - *timer->TA0CCR2) / (double)cmp;
  160. break;
  161. }
  162. default: break;
  163. }
  164. }
  165. *timer->TA0R = (uint16_t)value;
  166. }
  167. /*
  168. static double last_period = 0;
  169. static double last_pulse_width = 0;
  170. // Figure Out Frequency in up mode
  171. if (timer->compare_mode_0) {
  172. if (timer->mode_0 == UP_MODE) {
  173. uint16_t period_ct = *timer->TA0CCR0 + 1;
  174. uint64_t frequency = emu->cpu->bcm->mclk_freq;
  175. double period = (1.0/frequency) * period_ct;// In seconds
  176. double pulse_width = (1.0/frequency) * (*timer->TA0CCR1);
  177. double duty_cycle = pulse_width / period;
  178. // printf("period: %lf\npulse_width: %lf\nduty: %lf%%\n",
  179. // period, pulse_width, duty_cycle);
  180. if (last_period != period || last_pulse_width != pulse_width) {
  181. if (period >= 0.015 && period <= 0.025) { // 0.020 is sweet spot 50 Hz
  182. //printf("period: %lf, last_period: %lf\n", period, last_period);
  183. //printf("pw: %lf, last_pw: %lf\n", pulse_width, last_pulse_width);
  184. if (pulse_width < 0.0009) {
  185. // Send Control for 0 degrees
  186. //print_console(emu, "0 degrres\n");
  187. uint8_t byte = 0;
  188. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  189. }
  190. else if (pulse_width < 0.0012) {
  191. // Send Control for 30 Degrees
  192. //print_console(emu, "30 degrres\n");
  193. uint8_t byte = 30;
  194. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  195. }
  196. else if (pulse_width < 0.0015) {
  197. // Send Control for 60 degrees
  198. uint8_t byte = 60;
  199. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  200. }
  201. else if (pulse_width < 0.0018) {
  202. // Send Control for 90 degrees
  203. //print_console(emu, "90 degrres\n");
  204. uint8_t byte = 90;
  205. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  206. }
  207. else if (pulse_width < 0.0021) {
  208. // Send Control for 120 degrees
  209. uint8_t byte = 120;
  210. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  211. }
  212. else if (pulse_width >= 0.0021) {
  213. // Send Control for 150 degrees
  214. uint8_t byte = 150;
  215. send_control(emu, SERVO_MOTOR, (void *)&byte, 1);
  216. }
  217. }
  218. }
  219. if (OUTMOD1 == 0b111) { // RESET/SET
  220. uint16_t pulse_width = *timer->TA0CCR1;
  221. }
  222. last_period = period;
  223. last_pulse_width = pulse_width;
  224. }
  225. }
  226. */
  227. if (!timer->timer_0_running && MC0 != 0 && (*timer->TA0CCR0 > 0 || timer->mode_0 == CONTINOUS_MODE) ) {
  228. //print_console(emu, "START TIMER\n");
  229. // puts("TimerA0 started");
  230. timer->timer_0_running = true;
  231. timer->timer_0_start = cpu->nsecs;
  232. //pthread_t pp;
  233. //if(pthread_create(&pp, NULL, timer_A0_thread , (void*)emu)){
  234. //printf("ErrorcreatingDCOthread\n");
  235. //exit(1);
  236. //}
  237. }
  238. if(timer->timer_0_running && (MC0 == 0 || !(*timer->TA0CCR0 > 0 || timer->mode_0 == CONTINOUS_MODE))) {
  239. // puts("TimerA0 stopped");
  240. timer->timer_0_running = false;
  241. timer->timer_0_freq = 0;
  242. timer->timer_0_duty = 0;
  243. }
  244. }
  245. void *timer_A0_thread (void *data)
  246. {
  247. Emulator *emu = (Emulator *) data;
  248. Timer_a *timer = emu->cpu->timer_a;
  249. uint64_t counter;
  250. bool high = false;
  251. while (true) {
  252. high = true;
  253. counter = 0;
  254. while (true) {
  255. if ( counter == (*timer->TA0CCR1) ) {
  256. high = false;
  257. }
  258. else if ( counter == (*timer->TA0CCR0 + 1) ) {
  259. break;
  260. }
  261. mclk_wait_cycles(emu, 1);
  262. counter++;
  263. high ? printf("-") : printf("_");
  264. fflush(stdout);
  265. }
  266. }
  267. return NULL;
  268. }
  269. void setup_timer_a (Emulator *emu)
  270. {
  271. Cpu *cpu = emu->cpu;
  272. Timer_a *timer = cpu->timer_a;
  273. // Configure Timer_A0 Registers
  274. const uint16_t TA0CTL_VLOC = 0x160;
  275. const uint16_t TA0R_VLOC = 0x170;
  276. const uint16_t TA0CCTL0_VLOC = 0x162;
  277. const uint16_t TA0CCR0_VLOC = 0x172;
  278. const uint16_t TA0CCTL1_VLOC = 0x164;
  279. const uint16_t TA0CCR1_VLOC = 0x174;
  280. const uint16_t TA0CCTL2_VLOC = 0x166;
  281. const uint16_t TA0CCR2_VLOC = 0x176;
  282. const uint16_t TA0IV_VLOC = 0x12E;
  283. *(timer->TA0CTL = (uint16_t *) get_addr_ptr(TA0CTL_VLOC)) = 0;
  284. *(timer->TA0R = (uint16_t *) get_addr_ptr(TA0R_VLOC)) = 0;
  285. *(timer->TA0CCTL0 = (uint16_t *) get_addr_ptr(TA0CCTL0_VLOC)) = 0;
  286. *(timer->TA0CCR0 = (uint16_t *) get_addr_ptr(TA0CCR0_VLOC)) = 0;
  287. *(timer->TA0CCTL1 = (uint16_t *) get_addr_ptr(TA0CCTL1_VLOC)) = 0;
  288. *(timer->TA0CCR1 = (uint16_t *) get_addr_ptr(TA0CCR1_VLOC)) = 0;
  289. *(timer->TA0CCTL2 = (uint16_t *) get_addr_ptr(TA0CCTL2_VLOC)) = 0;
  290. *(timer->TA0CCR2 = (uint16_t *) get_addr_ptr(TA0CCR2_VLOC)) = 0;
  291. *(timer->TA0IV = (uint16_t *) get_addr_ptr(TA0IV_VLOC)) = 0;
  292. // Configure Timer_A1 Registers
  293. const uint16_t TA1CTL_VLOC = 0x180;
  294. const uint16_t TA1R_VLOC = 0x190;
  295. const uint16_t TA1CCTL0_VLOC = 0x182;
  296. const uint16_t TA1CCR0_VLOC = 0x192;
  297. const uint16_t TA1CCTL1_VLOC = 0x184;
  298. const uint16_t TA1CCR1_VLOC = 0x194;
  299. const uint16_t TA1CCTL2_VLOC = 0x186;
  300. const uint16_t TA1CCR2_VLOC = 0x196;
  301. const uint16_t TA1IV_VLOC = 0x11E;
  302. *(timer->TA1CTL = (uint16_t *) get_addr_ptr(TA1CTL_VLOC)) = 0;
  303. *(timer->TA1R = (uint16_t *) get_addr_ptr(TA1R_VLOC)) = 0;
  304. *(timer->TA1CCTL0 = (uint16_t *) get_addr_ptr(TA1CCTL0_VLOC)) = 0;
  305. *(timer->TA1CCR0 = (uint16_t *) get_addr_ptr(TA1CCR0_VLOC)) = 0;
  306. *(timer->TA1CCTL1 = (uint16_t *) get_addr_ptr(TA1CCTL1_VLOC)) = 0;
  307. *(timer->TA1CCR1 = (uint16_t *) get_addr_ptr(TA1CCR1_VLOC)) = 0;
  308. *(timer->TA1CCTL2 = (uint16_t *) get_addr_ptr(TA1CCTL2_VLOC)) = 0;
  309. *(timer->TA1CCR2 = (uint16_t *) get_addr_ptr(TA1CCR2_VLOC)) = 0;
  310. *(timer->TA1IV = (uint16_t *) get_addr_ptr(TA1IV_VLOC)) = 0;
  311. // Configure other
  312. timer->source_0 = 0b10;
  313. timer->timer_0_running = false;
  314. timer->timer_0_start = 0;
  315. timer->timer_0_freq = 0.0;
  316. timer->timer_0_duty = 0.0;
  317. timer->source_1 = 0b10;
  318. timer->timer_1_running = false;
  319. }
  320. /* POWER UP CLEAR (PUC)
  321. *
  322. * A PUC is always generated when a POR is generated, but a POR is not
  323. * generated by a PUC. The following events trigger a PUC:
  324. *
  325. * A POR signal
  326. * Watchdog timer expiration when in watchdog mode only
  327. * Watchdog timer security key violation
  328. * A Flash memory security key violation
  329. * A CPU instruct fetch from the peripheral address range 0h to 01FFh
  330. void power_up_clear () {
  331. *P1OUT = *P1DIR = *P1IFG = *P1IE = *P1SEL = *P1SEL2 = *P1REN = 0;
  332. }
  333. */