ThePhilleBoy

HDD clock with DS1307

Nov 27th, 2012
1,158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.36 KB | None | 0 0
  1. #include "Wire.h"
  2. #define DS1307_ADDRESS 0x68
  3. byte zero = 0x00; //workaround for issue #527
  4.  
  5. #ifndef F_CPU
  6. #define F_CPU 16000000UL // 16 MHz
  7. #endif
  8.  
  9. #include <stdlib.h>
  10. #include <avr/io.h>
  11. #include <avr/interrupt.h>
  12. #include <util/delay.h>
  13.  
  14. // arduino redefines int, which bugs out stdio.h (needed for sscanf)
  15. // see: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207028702/3
  16. #undef int
  17. #include <stdio.h>
  18.  
  19. // The number of "pie slices" that make up a single image around the platter
  20. #define DIVISIONS 0xFF
  21.  
  22. // Red pin, on PORTD
  23. #define RED 3
  24.  
  25. // Green Pin, on PORTD
  26. #define GRN 4
  27.  
  28. // Blue pin, on PORTD
  29. #define BLU 5
  30.  
  31. // Macro used to communicate serial status
  32. #define OK 1
  33.  
  34. // Number of pages in frame buffer
  35. #define PAGES 2
  36.  
  37. // Helper macro to build LED values for PORTD
  38. #define RGB(R,G,B) (R << RED | G << GRN | B << BLU)
  39.  
  40. // The timers are configured with the prescaler set to 8, which means every
  41. // 8 clock cycles equals on tick on the counter. This is a constant to help
  42. // convert timer cycles back to real time.
  43. #define FREQ_DIV_8 (F_CPU / 8)
  44.  
  45. // Defines how many ticks a millisecond equals on our clock
  46. #define MILLITICK (FREQ_DIV_8 * .001)
  47.  
  48. // I have found that the sensor in my rig is prone to triggering the interrupt
  49. // immediately after a real signal, likely related to capactive effects. This
  50. // tricks the system into thinking the platter is suddenly traveling a lot
  51. // faster, and can cause visible glitches. A 15K RPM drive spins 250 times a
  52. // second, where a single revolution requires 4ms. 4ms is exactly 8000 timer
  53. // cycles on our timer, which means anything half of 8000 is going faster than
  54. // any known HD. If such a value is captured, it is ignored.
  55. #define SPURIOUS_INT (2 * MILLITICK)
  56.  
  57. // Helper macros for frobbing bits
  58. #define bitset(var,bitno) ((var) |= (1 << (bitno)))
  59. #define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))
  60. #define bittst(var,bitno) (var& (1 << (bitno)))
  61.  
  62. // It is technically possible to change the number of divisions, even
  63. // though this is not currently implemented. This const serves as a place
  64. // holder for future enhancements.
  65. const unsigned char divisions = DIVISIONS;
  66.  
  67. // The current slice being drawn
  68. volatile unsigned char current_slice;
  69.  
  70. // The period of the platter in timer ticks
  71. int period;
  72.  
  73. // The value of the hidden page
  74. volatile int page_hidden;
  75.  
  76. // The value of the visible page
  77. volatile int page_visible;
  78.  
  79. // A flag representing the need for the pages to be flipped
  80. volatile unsigned char page_flip_flag;
  81.  
  82. // The double buffered frame buffer
  83. unsigned char FrameBuffer[PAGES][DIVISIONS];
  84.  
  85. /**
  86. ** FrameBuffer / Page routines
  87. **
  88. ** The framebuffer is double buffered, which allows you to write updates
  89. ** to the "hidden" page while the code draws from the "visible" page.
  90. **
  91. ** page_flip() makes the hidden page the visible page, and vice-versa.
  92. **
  93. ** copy_page() allows you to copy the visible page back to the hidden page,
  94. ** so you don't have to redraw the entire frame if you are just making a
  95. ** small change.
  96. **
  97. ** clear_page() clears the hidden page.
  98. **
  99. ** write_page() writes to the hidden page.
  100. **
  101. ** See RunStartupDisplay() for a simple example.
  102. **/
  103.  
  104. // sit and wait for the page to be flipped
  105. void __inline__ wait_for_page_flip(void)
  106. {
  107. while (page_flip_flag) {}
  108. }
  109.  
  110. // request a page flip, and wait for the sensor interrupt to flip the page
  111. void __inline__ flip_page(void)
  112. {
  113. page_flip_flag = 1;
  114. wait_for_page_flip();
  115. }
  116.  
  117. // copy the visible page to the hidden page
  118. void __inline__ copy_page(void)
  119. {
  120. int x;
  121. for(x = 0; x < divisions; x++)
  122. {
  123. FrameBuffer[page_hidden][x] = FrameBuffer[page_visible][x];
  124. }
  125. }
  126.  
  127. // write a value to the hidden page
  128. void __inline__ write_page(unsigned char slice, unsigned char val)
  129. {
  130. FrameBuffer[page_hidden][slice] = val;
  131. }
  132.  
  133. // clear the hidden page
  134. void clear_page(void)
  135. {
  136. int x;
  137. for(x = 0; x < divisions; x += 1)
  138. {
  139. FrameBuffer[page_hidden][x] = 0;
  140. }
  141. }
  142.  
  143. // called by the interrupt to flip to the next page
  144. void __inline__ flip_to_next_page(void)
  145. {
  146. if (page_flip_flag)
  147. {
  148. page_visible = page_hidden;
  149. page_hidden = !page_hidden;
  150. page_flip_flag = 0;
  151. }
  152. }
  153.  
  154.  
  155. // Configure the Serial Port, LED Pins, Timers, and Hardware Interrupt
  156. void SetupHardware(void)
  157. {
  158. // setup serial
  159. //Serial.begin(9600);
  160.  
  161. //Serial.print("[");
  162. // setup output
  163. pinMode(RED, OUTPUT);
  164. pinMode(GRN, OUTPUT);
  165. pinMode(BLU, OUTPUT);
  166. //Serial.print("L");
  167.  
  168. // disable global interrupts
  169. cli();
  170.  
  171. // setup timer0 - 8bit
  172. // resonsible for timing the LEDs
  173. TCCR0A = 0;
  174. TCCR0B = 0;
  175. // select CTC mode
  176. bitset(TCCR0A, WGM01);
  177. // select prescaler clk / 8
  178. bitset(TCCR0B, CS01);
  179. // enable compare interrupt
  180. bitset(TIMSK0, OCIE0A);
  181. //Serial.print("0");
  182.  
  183. // setup timer1 - 16bit
  184. // responsible for timing the rotation of the platter
  185. TCCR1B = 0;
  186. TCCR1A = 0;
  187. // select prescaler clk / 8
  188. bitset(TCCR1B, CS11);
  189. // reset timer
  190. TCNT1 = 0;
  191. // enable overflow interrupt
  192. bitset(TIMSK1, TOIE1);
  193. //Serial.print("1");
  194.  
  195. // configure the platter interrupt PIN
  196. // int0, on any change
  197. EICRA = _BV(ISC00);
  198. //EICRA = _BV(ISC01);
  199. // Enable the hardware interrupt.
  200. EIMSK |= _BV(INT0);
  201. //Serial.print("G");
  202.  
  203. // set the rotational period to 0
  204. period = 0;
  205.  
  206. // init pages
  207. init_pages();
  208.  
  209. // enable global interrupts
  210. sei();
  211.  
  212. /*Serial.println("]");
  213. Serial.flush();
  214. */
  215. }
  216.  
  217. // Simple animation to demonstrate the system is working
  218. void RunStartupDisplay(void)
  219. {
  220. int color;
  221. int slice;
  222.  
  223. clear_page();
  224. flip_page();
  225.  
  226. for (color = 0; color < 7; color++)
  227. {
  228. for (slice = 0; slice < divisions; slice += 2)
  229. {
  230. switch(color)
  231. {
  232. case 0:
  233. /* red */
  234. write_page(slice, _BV(RED));
  235. write_page(slice+1, _BV(RED));
  236. break;
  237. case 1:
  238. /* green */
  239. write_page(slice, _BV(GRN));
  240. write_page(slice+1, _BV(GRN));
  241. break;
  242. case 2:
  243. /* blue */
  244. write_page(slice, _BV(BLU));
  245. write_page(slice+1, _BV(BLU));
  246. break;
  247. case 3:
  248. //White
  249. write_page(slice, RGB(1,1,1));
  250. write_page(slice+1, RGB(1,1,1));
  251. break;
  252. case 4:
  253. //purple
  254. write_page(slice, RGB(1,0,1));
  255. write_page(slice+1, RGB(1,0,1));
  256. break;
  257. case 5:
  258. write_page(slice, RGB(0,1,1));
  259. write_page(slice+1, RGB(0,1,1));
  260. break;
  261. case 6:
  262. /* black */
  263. write_page(slice, 0);
  264. write_page(slice+1, 0);
  265. break;
  266. }
  267. flip_page();
  268. copy_page();
  269. }
  270. }
  271.  
  272. clear_page();
  273. flip_page();
  274. }
  275.  
  276. // Go through all pages of the frame buffer, and set them to 0
  277. void init_pages(void)
  278. {
  279. int page;
  280. int x;
  281. for(page = 0; page < PAGES; page += 1)
  282. {
  283. for(x = 0; x < divisions; x += 1)
  284. {
  285. FrameBuffer[page][x] = 0;
  286. }
  287. }
  288. page_hidden = 0;
  289. page_flip_flag = 0;
  290. }
  291.  
  292. // Simple test pattern displaying all the available drawable slices.
  293. void InitTestPattern2(void)
  294. {
  295. clear_page();
  296.  
  297. int x;
  298. for(x = 0; x < divisions; x++)
  299. {
  300. switch (x % 8)
  301. {
  302. case 0:
  303. write_page(x, RGB(0,0,0));
  304. break;
  305. case 1:
  306. write_page(x, RGB(1,0,0));
  307. break;
  308. case 2:
  309. write_page(x, RGB(0,1,0));
  310. break;
  311. case 3:
  312. write_page(x, RGB(0,0,1));
  313. break;
  314. case 4:
  315. write_page(x, RGB(1,1,0));
  316. break;
  317. case 5:
  318. write_page(x, RGB(1,0,1));
  319. break;
  320. case 6:
  321. write_page(x, RGB(0,1,1));
  322. break;
  323. case 7:
  324. write_page(x, RGB(1,1,1));
  325. break;
  326. }
  327. }
  328. flip_page();
  329. }
  330.  
  331. void InitTestPattern1(void)
  332. {
  333. int x;
  334. for(x = 0; x < divisions; x++)
  335. {
  336. switch (x / (divisions / 8))
  337. {
  338. case 0:
  339. write_page(x, RGB(0,0,0));
  340. break;
  341. case 1:
  342. write_page(x, RGB(1,0,0));
  343. break;
  344. case 2:
  345. write_page(x, RGB(0,1,0));
  346. break;
  347. case 3:
  348. write_page(x, RGB(0,0,1));
  349. break;
  350. case 4:
  351. write_page(x, RGB(1,1,0));
  352. break;
  353. case 5:
  354. write_page(x, RGB(1,0,1));
  355. break;
  356. case 6:
  357. write_page(x, RGB(0,1,1));
  358. break;
  359. case 7:
  360. default:
  361. write_page(x, RGB(1,1,1));
  362. break;
  363. }
  364. }
  365. }
  366.  
  367. // Top level setup, called by the Arduino core
  368. void setup(void)
  369. {
  370. SetupHardware();
  371. RunStartupDisplay();
  372. Wire.begin();
  373. setDateTime(); //MUST CONFIGURE IN FUNCTION
  374. }
  375.  
  376.  
  377. // Top level loop, call by the Arduino core
  378. void loop(void)
  379. {
  380. printDate();
  381. int cmd;
  382. int slice, value;
  383. int okval = OK;
  384.  
  385. // Simple test pattern displaying all the available drawable slices.
  386. //InitTestPattern2();
  387.  
  388. }
  389.  
  390.  
  391. // This interrupt is called on every pulse of the sensor, which represents
  392. // one full rotation of the platter. It is responsible for timing the
  393. // revolution, and for initiating the first draw instance.
  394. ISR(INT0_vect)
  395. {
  396. // Capture the 16bit count on timer1, this represents one revolution
  397. period = TCNT1;
  398. // If the period is shorter than our threshold, don't do anything
  399. if(period < SPURIOUS_INT)
  400. {
  401. return;
  402. }
  403. // Reset timer1 so it can clock the next revolution
  404. TCNT1 = 0;
  405. // Reset timer0 so it can start to accurately paint the slot
  406. TCNT0 = 0;
  407. // If there is a page flip request, flip to the next page
  408. flip_to_next_page();
  409. // Write out the first slice to the LEDs to PORTD
  410. PORTD = FrameBuffer[page_visible][0];
  411. // Divide the time of single platter rotation by the number of drawable
  412. // divisions
  413. OCR0A = (period / divisions);
  414. // Set our current slice to 1, since we just drew slice 0
  415. current_slice = 1;
  416. }
  417.  
  418. // This interrupt is called every time timer0 counts up to the 8bit value
  419. // stored in the register "ORC0A", which is configured in INT0 interrupt.
  420. // It is responsible for drawing out all the slices of the frame buffer
  421. // during the exact moment the slot is in its proper rotational position.
  422. // Using a 7200RPM drive with 255 divisions, this interrupt is called
  423. // 31,200 times a second.
  424. ISR(TIMER0_COMPA_vect) {
  425. // Write out the LED value to the Frame Buffer
  426. PORTD = FrameBuffer[page_visible][current_slice];
  427. // Increment current slice, making sure to wrap it if it
  428. // has accidently gotten too large
  429. current_slice = ((current_slice + 1) % divisions);
  430. }
  431.  
  432. // If the platter spin time overflows timer1, this is called
  433. ISR(TIMER1_OVF_vect) {
  434. }
  435.  
  436. void setDateTime(){
  437.  
  438. byte second = 40; //0-59
  439. byte minute = 16; //0-59
  440. byte hour = 21; //0-23
  441. byte weekDay = 3; //1-7
  442. byte monthDay = 25; //1-31
  443. byte month = 4; //1-12
  444. byte year = 12; //0-99
  445.  
  446. Wire.beginTransmission(DS1307_ADDRESS);
  447. Wire.write(zero); //stop Oscillator
  448.  
  449. Wire.write(decToBcd(second));
  450. Wire.write(decToBcd(minute));
  451. Wire.write(decToBcd(hour));
  452. Wire.write(decToBcd(weekDay));
  453. Wire.write(decToBcd(monthDay));
  454. Wire.write(decToBcd(month));
  455. Wire.write(decToBcd(year));
  456.  
  457. Wire.write(zero); //start
  458.  
  459. Wire.endTransmission();
  460.  
  461. }
  462.  
  463. byte decToBcd(byte val){
  464. // Convert normal decimal numbers to binary coded decimal
  465. return ( (val/10*16) + (val%10) );
  466. }
  467.  
  468. byte bcdToDec(byte val) {
  469. // Convert binary coded decimal to normal decimal numbers
  470. return ( (val/16*10) + (val%16) );
  471. }
  472.  
  473. void printDate(){
  474.  
  475. // Reset the register pointer
  476. Wire.beginTransmission(DS1307_ADDRESS);
  477. Wire.write(zero);
  478. Wire.endTransmission();
  479.  
  480. Wire.requestFrom(DS1307_ADDRESS, 7);
  481.  
  482. int second = bcdToDec(Wire.read());
  483. int minute = bcdToDec(Wire.read());
  484. int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  485. int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  486. int monthDay = bcdToDec(Wire.read());
  487. int month = bcdToDec(Wire.read());
  488. int year = bcdToDec(Wire.read());
  489.  
  490. if(hour > 12)
  491. {
  492. hour-=12;
  493. }
  494.  
  495. hour = (divisions * (hour / 12.0) + (divisions / 12.0) * (minute / 60.0));
  496. minute = (divisions * (minute / 60.0));
  497. second = (divisions * (second / 60.0));
  498.  
  499.  
  500. for(int i = 0; i <= 255; i++)
  501. {
  502. write_page(i, RGB(1,0,1));
  503. }
  504.  
  505. clockNums();
  506.  
  507. for(int i = (hour-3); i < (hour + 3); i++)
  508. {
  509. write_page(i, RGB(1,0,0));
  510. }
  511.  
  512. for(int i =(minute-2); i < (minute + 2); i++)
  513. {
  514. write_page(i, RGB(0,1,0));
  515. }
  516.  
  517. for(int i =(second-1); i< (second+1); i++)
  518. {
  519. write_page(i, RGB(1,1,1));
  520. }
  521. flip_page();
  522. clear_page();
  523. }
  524.  
  525.  
  526. void clockNums()
  527. {
  528. for(int i =63; i< (66); i++)
  529. {
  530. write_page(i, RGB(0,0,0));
  531. }
  532.  
  533. for(int i = 0; i< (2); i++)
  534. {
  535. write_page(i, RGB(0,0,0));
  536. write_page(255, RGB(0,0,0));
  537. }
  538.  
  539. for(int i = 127; i< 130; i++)
  540. {
  541. write_page(i, RGB(0,0,0));
  542. }
  543.  
  544. for(int i = 190; i< 193; i++)
  545. {
  546. write_page(i, RGB(0,0,0));
  547. }
  548. write_page(22, RGB(0,0,0));
  549. write_page(43, RGB(0,0,0));
  550. write_page(85, RGB(0,0,0));
  551. write_page(106, RGB(0,0,0));
  552. write_page(149, RGB(0,0,0));
  553. write_page(170, RGB(0,0,0));
  554. write_page(213, RGB(0,0,0));
  555. write_page(234, RGB(0,0,0));
  556.  
  557. }
Advertisement
Add Comment
Please, Sign In to add comment