Picadae hardware and control code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

i2c_timer_pwm_1.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. //| Copyright: (C) 2018-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. /*
  4. AT TINY 85
  5. +--\/--+
  6. RESET _| 1 8 |_ +5V
  7. ~OC1B HOLD DDB3 _| 2 7 |_ SCL
  8. OC1B ONSET DDB4 _| 3 6 |_ DDB1 LED
  9. GND _| 4 5 |_ SDA
  10. +------+
  11. * = Serial and/or programming pins on Arduino as ISP
  12. */
  13. // This program acts as the device (slave) for the control program i2c/a2a/c_ctl
  14. #define F_CPU 8000000L
  15. #include <stdio.h>
  16. #include <avr/io.h>
  17. #include <util/delay.h>
  18. #include <avr/interrupt.h>
  19. #include "usiTwiSlave.h"
  20. #define I2C_SLAVE_ADDRESS 0x8 // the 7-bit address (remember to change this when adapting this example)
  21. enum
  22. {
  23. kTmr0_Prescale_idx = 0, // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
  24. kTmr0_Coarse_idx = 1, //
  25. kTmr0_Fine_idx = 2, //
  26. kPWM0_Duty_idx = 3, //
  27. kPWM0_Freq_idx = 4, // 1-4 = clock divider=1=1,2=8,3=64,4=256,5=1024
  28. kCS13_10_idx = 5, // Timer 1 Prescalar (CS13,CS12,CS11,CS10) from Table 12-5 pg 89 (0-15) prescaler = pow(2,val-1), 0=stop,1=1,2=2,3=4,4=8,....14=8192,15=16384 pre_scaled_hz = clock_hz/value
  29. kTmr1_Coarse_idx = 6, // count of times timer0 count to 255 before OCR1C is set to Tmr0_Fine
  30. kTmr1_Fine_idx = 7, // OCR1C timer match value
  31. kPWM1_Duty_idx = 8, //
  32. kPWM1_Freq_idx = 9, //
  33. kTable_Addr_idx = 10, // Next table address to read/write
  34. kTable_Coarse_idx = 11, // Next table coarse value to read/write
  35. kTable_Fine_idx = 12, // Next table fine value to read/write
  36. kMax_idx
  37. };
  38. volatile uint8_t ctl_regs[] =
  39. {
  40. 4, // 0 (1-5) 4=32us per tick
  41. 123, // 1 (0-255) Timer 0 Coarse Value
  42. 8, // 2 (0-255) Timer 0 Fine Value
  43. 127, // 3 (0-255) Duty cycle
  44. 4, // 4 (1-4) PWM Frequency (clock pre-scaler)
  45. 9, // 5 9=32 us period w/ 8Mhz clock (timer tick rate)
  46. 123, // 6 (0-255) Tmr1_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
  47. 8, // 7 (0-254) Tmr1_Fine OCR1C value on final phase before triggering timer
  48. 127, // 8 (0-255) PWM1 Duty cycle
  49. 254, // 9 (0-255) PWM1 Frequency (123 hz)
  50. 0, // 10 (0-127) Next table addr to read/write
  51. 0, // 11 (0-255) Next table coarse value to write
  52. 0, // 12 (0-255) Next table fine value to write
  53. };
  54. #define tableN 256
  55. uint8_t table[ tableN ];
  56. //------------------------------------------------------------------------------
  57. //------------------------------------------------------------------------------
  58. //------------------------------------------------------------------------------
  59. //
  60. // EEPROM
  61. //
  62. void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
  63. {
  64. // Wait for completion of previous write
  65. while(EECR & (1<<EEPE))
  66. {}
  67. EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode
  68. EEAR = ucAddress; // Set up address and data registers
  69. EEDR = ucData;
  70. EECR |= (1<<EEMPE); // Write logical one to EEMPE
  71. EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
  72. }
  73. uint8_t EEPROM_read(uint8_t ucAddress)
  74. {
  75. // Wait for completion of previous write
  76. while(EECR & (1<<EEPE))
  77. {}
  78. EEAR = ucAddress; // Set up address register
  79. EECR |= (1<<EERE); // Start eeprom read by writing EERE
  80. return EEDR; // Return data from data register
  81. }
  82. //------------------------------------------------------------------------------
  83. //------------------------------------------------------------------------------
  84. //------------------------------------------------------------------------------
  85. //
  86. // Read/Write table
  87. //
  88. // To write table value 42 to 127 (coarse) 64 (fine)
  89. //
  90. // w 8 kTable_Addr_idx 42
  91. // w 8 kTable_Coarse_idx 127
  92. // w 8 kTable_fine_idx 64
  93. //
  94. // TO read table value 42
  95. // w 8 kTable_Addr_idx 42
  96. // r 8 kTable_Coarse_idx -> 127
  97. // r 8 kTable_Fine_idx -> 64
  98. #define eeprom_addr( addr ) (kMax_idx + (addr))
  99. void table_write_cur_value( void )
  100. {
  101. uint8_t tbl_addr = ctl_regs[ kTable_Addr_idx ] * 2;
  102. table[ tbl_addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
  103. table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ];
  104. EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
  105. EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]);
  106. }
  107. void table_load( void )
  108. {
  109. uint8_t i = 0;
  110. for(; i<128; ++i)
  111. {
  112. uint8_t tbl_addr = i*2;
  113. table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
  114. table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
  115. }
  116. }
  117. void restore_memory_from_eeprom( void )
  118. {
  119. /*
  120. uint8_t i;
  121. for(i=0; i<kMax_idx; ++i)
  122. {
  123. ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
  124. }
  125. */
  126. table_load();
  127. }
  128. //------------------------------------------------------------------------------
  129. //------------------------------------------------------------------------------
  130. //------------------------------------------------------------------------------
  131. //
  132. // Timer0
  133. //
  134. volatile uint8_t tmr0_state = 0; // 0=disabled 1=coarse mode, 2=fine mode
  135. volatile uint8_t tmr0_coarse_cur = 0;
  136. // Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
  137. void tmr0_reset()
  138. {
  139. // if a coarse count exists then go into coarse mode
  140. if( ctl_regs[kTmr0_Coarse_idx] > 0 )
  141. {
  142. tmr0_state = 1;
  143. OCR0A = 0xff;
  144. }
  145. else // otherwise go into fine mode
  146. {
  147. tmr0_state = 2;
  148. OCR0A = ctl_regs[kTmr0_Fine_idx];
  149. }
  150. tmr0_coarse_cur = 0;
  151. }
  152. ISR(TIMER0_COMPA_vect)
  153. {
  154. switch( tmr0_state )
  155. {
  156. case 0:
  157. // disabled
  158. break;
  159. case 1:
  160. // coarse mode
  161. if( ++tmr0_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
  162. {
  163. tmr0_state = 2;
  164. OCR0A = ctl_regs[kTmr0_Fine_idx];
  165. }
  166. break;
  167. case 2:
  168. // fine mode
  169. PINB = _BV(PINB4); // writes to PINB toggle the pins
  170. tmr0_reset(); // restart the timer
  171. break;
  172. }
  173. }
  174. void timer0_init()
  175. {
  176. TIMSK &= ~_BV(OCIE0A); // Disable interrupt TIMER1_OVF
  177. TCCR0A |= 0x02; // CTC mode
  178. TCCR0B |= ctl_regs[kTmr0_Prescale_idx]; // set the prescaler
  179. GTCCR |= _BV(PSR0); // Set the pre-scaler to the selected value
  180. tmr0_reset(); // set the timers starting state
  181. TIMSK |= _BV(OCIE0A); // Enable interrupt TIMER1_OVF
  182. }
  183. //------------------------------------------------------------------------------
  184. //------------------------------------------------------------------------------
  185. //------------------------------------------------------------------------------
  186. //
  187. // PWM (Timer0)
  188. //
  189. void pwm0_update()
  190. {
  191. OCR0B = ctl_regs[kPWM0_Duty_idx]; // 50% duty cycle
  192. TCCR0B |= ctl_regs[kPWM0_Freq_idx]; // PWM frequency pre-scaler
  193. }
  194. void pwm0_init()
  195. {
  196. // WGM[1:0] = 3 (TOP=255)
  197. // OCR0B = duty cycle (0-100%)
  198. // COM0A[1:0] = 2 non-inverted
  199. //
  200. TCCR0A |= 0x20 + 3; // 0x20=non-inverting 3=WGM bits Fast-PWM mode (0=Bot 255=Top)
  201. TCCR0B |= 0x00 + 4; // 3=256 pre-scaler 122Hz=1Mghz/(v*256) where v=64
  202. GTCCR |= _BV(PSR0); // Set the pre-scaler to the selected value
  203. pwm0_update();
  204. DDRB |= _BV(DDB1); // set direction on
  205. }
  206. //------------------------------------------------------------------------------
  207. //------------------------------------------------------------------------------
  208. //------------------------------------------------------------------------------
  209. //
  210. // Timer1
  211. //
  212. volatile uint8_t tmr1_state = 0;
  213. volatile uint8_t tmr1_coarse_cur = 0;
  214. static uint8_t tmr1_init_fl = 0;
  215. void tmr1_reset()
  216. {
  217. if( ctl_regs[kTmr1_Coarse_idx] > 0 )
  218. {
  219. tmr1_state = 1;
  220. OCR1C = 254;
  221. }
  222. else
  223. {
  224. tmr1_state = 2;
  225. OCR1C = ctl_regs[kTmr1_Fine_idx];
  226. }
  227. tmr1_coarse_cur = 0;
  228. }
  229. ISR(TIMER1_OVF_vect)
  230. {
  231. if( !tmr1_init_fl )
  232. {
  233. PORTB |= _BV(PINB3); // set PWM pin
  234. }
  235. else
  236. {
  237. switch( tmr1_state )
  238. {
  239. case 0:
  240. // disabled
  241. break;
  242. case 1:
  243. // coarse mode
  244. if( ++tmr1_coarse_cur >= ctl_regs[kTmr1_Coarse_idx] )
  245. {
  246. tmr1_state = 2;
  247. OCR1C = ctl_regs[kTmr1_Fine_idx];
  248. }
  249. break;
  250. case 2:
  251. // fine mode
  252. PINB = _BV(PINB4); // writes to PINB toggle the pins
  253. tmr1_reset();
  254. break;
  255. }
  256. }
  257. }
  258. void timer1_init()
  259. {
  260. TIMSK &= ~_BV(TOIE1); // Disable interrupt TIMER1_OVF
  261. OCR1A = 255; // Set to anything greater than OCR1C (the counter never gets here.)
  262. TCCR1 |= _BV(CTC1); // Reset TCNT1 to 0 when TCNT1==OCR1C
  263. TCCR1 |= _BV(PWM1A); // Enable PWM A (to generate overflow interrupts)
  264. TCCR1 |= ctl_regs[kCS13_10_idx] & 0x0f; //
  265. GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
  266. tmr1_reset();
  267. tmr1_init_fl = 1;
  268. TIMSK |= _BV(TOIE1); // Enable interrupt TIMER1_OVF
  269. }
  270. //------------------------------------------------------------------------------
  271. //------------------------------------------------------------------------------
  272. //------------------------------------------------------------------------------
  273. //
  274. // PWM1
  275. //
  276. // PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
  277. // but since these pins are not available this code uses
  278. // ISR's to redirect the output to PIN3
  279. void pwm1_update()
  280. {
  281. OCR1B = ctl_regs[kPWM1_Duty_idx]; // control duty cycle
  282. OCR1C = ctl_regs[kPWM1_Freq_idx]; // PWM frequency pre-scaler
  283. }
  284. ISR(TIMER1_COMPB_vect)
  285. {
  286. PORTB &= ~(_BV(PINB3)); // clear PWM pin
  287. }
  288. void pwm1_init()
  289. {
  290. TIMSK &= ~(_BV(OCIE1B) + _BV(TOIE1)); // Disable interrupts
  291. DDRB |= _BV(DDB3); // setup PB3 as output
  292. // set on TCNT1 == 0 // happens when TCNT1 matches OCR1C
  293. // clr on OCR1B == TCNT // happens when TCNT1 matches OCR1B
  294. // // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
  295. TCCR1 |= 9; // 32us period (256 divider) prescaler
  296. GTCCR |= _BV(PWM1B); // Enable PWM B and disconnect output pins
  297. GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
  298. pwm1_update();
  299. TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // Enable interrupts
  300. }
  301. //------------------------------------------------------------------------------
  302. //------------------------------------------------------------------------------
  303. //------------------------------------------------------------------------------
  304. // Tracks the current register pointer position
  305. volatile uint8_t reg_position = 0;
  306. const uint8_t reg_size = sizeof(ctl_regs);
  307. //
  308. // Read Request Handler
  309. //
  310. // This is called for each read request we receive, never put more
  311. // than one byte of data (with TinyWireS.send) to the send-buffer when
  312. // using this callback
  313. //
  314. void on_request()
  315. {
  316. uint8_t val = 0;
  317. switch( reg_position )
  318. {
  319. case kTable_Coarse_idx:
  320. val = table[ ctl_regs[kTable_Addr_idx]*2 + 0 ];
  321. break;
  322. case kTable_Fine_idx:
  323. val = table[ ctl_regs[kTable_Addr_idx]*2 + 1 ];
  324. break;
  325. default:
  326. // read and transmit the requestd position
  327. val = ctl_regs[reg_position];
  328. }
  329. usiTwiTransmitByte(val);
  330. // Increment the reg position on each read, and loop back to zero
  331. reg_position++;
  332. if (reg_position >= reg_size)
  333. {
  334. reg_position = 0;
  335. }
  336. }
  337. //
  338. // The I2C data received -handler
  339. //
  340. // This needs to complete before the next incoming transaction (start,
  341. // data, restart/stop) on the bus does so be quick, set flags for long
  342. // running tasks to be called from the mainloop instead of running
  343. // them directly,
  344. //
  345. void on_receive( uint8_t byteN )
  346. {
  347. if (byteN < 1)
  348. {
  349. // Sanity-check
  350. return;
  351. }
  352. if (byteN > TWI_RX_BUFFER_SIZE)
  353. {
  354. // Also insane number
  355. return;
  356. }
  357. // get the register index to read/write
  358. reg_position = usiTwiReceiveByte();
  359. byteN--;
  360. // If only one byte was received then this was a read request
  361. // and the buffer pointer (reg_position) is now set to return the byte
  362. // at this location on the subsequent call to on_request() ...
  363. if (!byteN)
  364. {
  365. return;
  366. }
  367. // ... otherwise this was a write request and the buffer
  368. // pointer is now pointing to the first byte to write to
  369. while(byteN--)
  370. {
  371. // write the value
  372. ctl_regs[reg_position] = usiTwiReceiveByte();
  373. // Set timer 1
  374. if( kTmr0_Prescale_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
  375. { timer0_init(); }
  376. else
  377. // Set PWM 0
  378. if( kPWM0_Duty_idx <= reg_position && reg_position <= kPWM0_Freq_idx )
  379. { pwm0_update(); }
  380. else
  381. // Set timer 1
  382. if( kCS13_10_idx <= reg_position && reg_position <= kTmr1_Fine_idx )
  383. { timer1_init(); }
  384. else
  385. // Set PWM 1
  386. if( kPWM1_Duty_idx <= reg_position && reg_position <= kPWM1_Freq_idx )
  387. { pwm1_update(); }
  388. else
  389. // Write table
  390. if( reg_position == kTable_Fine_idx )
  391. { table_write_cur_value(); }
  392. reg_position++;
  393. if (reg_position >= reg_size)
  394. {
  395. reg_position = 0;
  396. }
  397. }
  398. }
  399. int main(void)
  400. {
  401. cli(); // mask all interupts
  402. restore_memory_from_eeprom();
  403. DDRB |= _BV(DDB4) + _BV(DDB3) + _BV(DDB1); // setup PB4,PB3,PB1 as output
  404. PORTB &= ~(_BV(PINB4) + _BV(PINB3) + _BV(PINB1)); // clear output pins
  405. timer0_init();
  406. pwm1_init();
  407. // setup i2c library
  408. usi_onReceiverPtr = on_receive;
  409. usi_onRequestPtr = on_request;
  410. usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
  411. sei();
  412. PINB = _BV(PINB4); // writes to PINB toggle the pins
  413. _delay_ms(1000);
  414. PINB = _BV(PINB4); // writes to PINB toggle the pins
  415. while(1)
  416. {
  417. //_delay_ms(1000);
  418. if (!usi_onReceiverPtr)
  419. {
  420. // no onReceive callback, nothing to do...
  421. continue;
  422. }
  423. if (!(USISR & ( 1 << USIPF )))
  424. {
  425. // Stop not detected
  426. continue;
  427. }
  428. uint8_t amount = usiTwiAmountDataInReceiveBuffer();
  429. if (amount == 0)
  430. {
  431. // no data in buffer
  432. continue;
  433. }
  434. usi_onReceiverPtr(amount);
  435. }
  436. return 0;
  437. }