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_0.c 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. HOLD DDB3 _| 2 7 |_ SCL
  8. 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. kCS13_10_idx = 0, // 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
  24. kTmr0_Coarse_idx = 1, // count of times timer0 count to 255 before OCR1C is set to Tmr0_Fine
  25. kTmr0_Fine_idx = 2, // OCR1C timer match value
  26. kPWM_Duty_idx = 3, //
  27. kPWM_Freq_idx = 4, // 1-4 = clock divider=1=1,2=8,3=64,4=256,5=1024
  28. kTable_Addr_idx = 5, // Next table address to write
  29. kTable_Coarse_idx= 6, // Next table coarse value to write
  30. kTable_Fine_idx = 7, // Next table fine value to write
  31. kMax_idx
  32. };
  33. volatile uint8_t ctl_regs[] =
  34. {
  35. 9, // 0 9=32 us period w/ 8Mhz clock (timer tick rate)
  36. 123, // 1 (0-255) Tmr0_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
  37. 8, // 2 (0-254) Tmr0_Fine OCR1C value on final phase before triggering timer
  38. 127, // 3 (0-255) Duty cycle
  39. 4, // 4 (1-4) PWM Frequency (clock pre-scaler)
  40. 0, // 7 (0-127) Next table addr to read/write
  41. 0, // 5 (0-255) Next table coarse value to write
  42. 0, // 6 (0-255) Next table fine value to write
  43. };
  44. #define tableN 256
  45. uint8_t table[ tableN ];
  46. //------------------------------------------------------------------------------
  47. //------------------------------------------------------------------------------
  48. //------------------------------------------------------------------------------
  49. //
  50. // EEPROM
  51. //
  52. void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
  53. {
  54. // Wait for completion of previous write
  55. while(EECR & (1<<EEPE))
  56. {}
  57. EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode
  58. EEAR = ucAddress; // Set up address and data registers
  59. EEDR = ucData;
  60. EECR |= (1<<EEMPE); // Write logical one to EEMPE
  61. EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
  62. }
  63. uint8_t EEPROM_read(uint8_t ucAddress)
  64. {
  65. // Wait for completion of previous write
  66. while(EECR & (1<<EEPE))
  67. {}
  68. EEAR = ucAddress; // Set up address register
  69. EECR |= (1<<EERE); // Start eeprom read by writing EERE
  70. return EEDR; // Return data from data register
  71. }
  72. //------------------------------------------------------------------------------
  73. //------------------------------------------------------------------------------
  74. //------------------------------------------------------------------------------
  75. //
  76. // Read/Write table
  77. //
  78. #define eeprom_addr( addr ) (kMax_idx + (addr))
  79. void table_write( void )
  80. {
  81. uint8_t addr = ctl_regs[ kTable_Addr_idx ] * 2;
  82. table[ addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
  83. table[ addr+1 ] = ctl_regs[ kTable_Fine_idx ];
  84. EEPROM_write( eeprom_addr( addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
  85. EEPROM_write( eeprom_addr( addr+1 ), ctl_regs[ kTable_Fine_idx ]);
  86. }
  87. void table_load( void )
  88. {
  89. uint8_t i = 0;
  90. for(; i<128; ++i)
  91. {
  92. uint8_t addr = i*2;
  93. table[addr+0] = EEPROM_read( eeprom_addr(addr) );
  94. table[addr+1] = EEPROM_read( eeprom_addr(addr) );
  95. }
  96. }
  97. void restore_memory_from_eeprom( void )
  98. {
  99. uint8_t i;
  100. for(i=0; i<kMax_idx; ++i)
  101. {
  102. ctl_regs[i] = eeprom_read( eeprom_addr( i ) );
  103. }
  104. table_load();
  105. }
  106. //------------------------------------------------------------------------------
  107. //------------------------------------------------------------------------------
  108. //------------------------------------------------------------------------------
  109. //
  110. // PWM (Timer0)
  111. //
  112. void pwm0_update()
  113. {
  114. OCR0B = ctl_regs[kPWM_Duty_idx]; // 50% duty cycle
  115. TCCR0B |= ctl_regs[kPWM_Freq_idx]; // PWM frequency pre-scaler
  116. }
  117. void pwm0_init()
  118. {
  119. // WGM[1:0] = 3 (TOP=255)
  120. // OCR0B = duty cycle (0-100%)
  121. // COM0A[1:0] = 2 non-inverted
  122. //
  123. TCCR0A |= 0x20 + 3; // 0x20=non-inverting 3=WGM bits Fast-PWM mode (0=Bot 255=Top)
  124. TCCR0B |= 0x00 + 4; // 3=256 pre-scaler 122Hz=1Mghz/(v*256) where v=64
  125. pwm0_update();
  126. DDRB |= _BV(DDB1);
  127. }
  128. //------------------------------------------------------------------------------
  129. //------------------------------------------------------------------------------
  130. //------------------------------------------------------------------------------
  131. //
  132. // Timer1
  133. //
  134. volatile uint8_t tmr_state = 0;
  135. volatile uint8_t tmr_coarse_cur = 0;
  136. void tmr_reset()
  137. {
  138. if( ctl_regs[kTmr0_Coarse_idx] > 0 )
  139. {
  140. tmr_state = 1;
  141. OCR1C = 254;
  142. }
  143. else
  144. {
  145. tmr_state = 2;
  146. OCR1C = ctl_regs[kTmr0_Fine_idx];
  147. }
  148. tmr_coarse_cur = 0;
  149. }
  150. ISR(TIMER1_OVF_vect)
  151. {
  152. switch( tmr_state )
  153. {
  154. case 0:
  155. break;
  156. case 1:
  157. if( ++tmr_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
  158. {
  159. tmr_state = 2;
  160. OCR1C = ctl_regs[kTmr0_Fine_idx];
  161. }
  162. break;
  163. case 2:
  164. PINB = _BV(PINB4) + _BV(PINB1); // writes to PINB toggle the pins
  165. tmr_reset();
  166. break;
  167. }
  168. }
  169. void timer1_init()
  170. {
  171. TIMSK &= ~_BV(TOIE1); // Disable interrupt TIMER1_OVF
  172. OCR1A = 255; // Set to anything greater than OCR1C (the counter never gets here.)
  173. TCCR1 |= _BV(CTC1); // Reset TCNT1 to 0 when TCNT1==OCR1C
  174. TCCR1 |= _BV(PWM1A); // Enable PWM A
  175. TCCR1 |= ctl_regs[kCS13_10_idx] & 0x0f; //
  176. GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
  177. tmr_reset();
  178. TIMSK |= _BV(TOIE1); // Enable interrupt TIMER1_OVF
  179. }
  180. //------------------------------------------------------------------------------
  181. //------------------------------------------------------------------------------
  182. //------------------------------------------------------------------------------
  183. // Tracks the current register pointer position
  184. volatile uint8_t reg_position = 0;
  185. const uint8_t reg_size = sizeof(ctl_regs);
  186. //
  187. // Read Request Handler
  188. //
  189. // This is called for each read request we receive, never put more
  190. // than one byte of data (with TinyWireS.send) to the send-buffer when
  191. // using this callback
  192. //
  193. void on_request()
  194. {
  195. uint8_t val = 0;
  196. switch( reg_position )
  197. {
  198. case kTable_Coarse_idx:
  199. val = table[ reg_position*2 + 0 ];
  200. break;
  201. case kTable_Fine_idx:
  202. val = table[ reg_position*2 + 1 ];
  203. break;
  204. default:
  205. // read and transmit the requestd position
  206. val = ctl_regs[reg_position];
  207. }
  208. usiTwiTransmitByte(val);
  209. // Increment the reg position on each read, and loop back to zero
  210. reg_position++;
  211. if (reg_position >= reg_size)
  212. {
  213. reg_position = 0;
  214. }
  215. }
  216. //
  217. // The I2C data received -handler
  218. //
  219. // This needs to complete before the next incoming transaction (start,
  220. // data, restart/stop) on the bus does so be quick, set flags for long
  221. // running tasks to be called from the mainloop instead of running
  222. // them directly,
  223. //
  224. void on_receive( uint8_t byteN )
  225. {
  226. if (byteN < 1)
  227. {
  228. // Sanity-check
  229. return;
  230. }
  231. if (byteN > TWI_RX_BUFFER_SIZE)
  232. {
  233. // Also insane number
  234. return;
  235. }
  236. // get the register index to read/write
  237. reg_position = usiTwiReceiveByte();
  238. byteN--;
  239. // If only one byte was received then this was a read request
  240. // and the buffer pointer (reg_position) is now set to return the byte
  241. // at this location on the subsequent call to on_request() ...
  242. if (!byteN)
  243. {
  244. return;
  245. }
  246. // ... otherwise this was a write request and the buffer
  247. // pointer is now pointing to the first byte to write to
  248. while(byteN--)
  249. {
  250. ctl_regs[reg_position] = usiTwiReceiveByte();
  251. // Set timer
  252. if( kCS13_10_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
  253. { timer1_init(); }
  254. else
  255. // Set PWM
  256. if( kPWM_Duty_idx <= reg_position && reg_position <= kPWM_Freq_idx )
  257. { pwm0_update(); }
  258. else
  259. // Write table
  260. if( reg_position == kTable_Fine_idx )
  261. { table_write(); }
  262. reg_position++;
  263. if (reg_position >= reg_size)
  264. {
  265. reg_position = 0;
  266. }
  267. }
  268. }
  269. int main(void)
  270. {
  271. cli(); // mask all interupts
  272. DDRB |= _BV(DDB4) + _BV(DDB1); // setup PB4 as output
  273. PORTB &= ~(_BV(PINB4) + _BV(PINB1));
  274. timer1_init();
  275. pwm0_init();
  276. // setup i2c library
  277. usi_onReceiverPtr = on_receive; //on_receive;
  278. usi_onRequestPtr = on_request;
  279. usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
  280. sei();
  281. PINB = _BV(PINB4); // writes to PINB toggle the pins
  282. _delay_ms(1000);
  283. PINB = _BV(PINB4); // writes to PINB toggle the pins
  284. while(1)
  285. {
  286. //_delay_ms(1000);
  287. if (!usi_onReceiverPtr)
  288. {
  289. // no onReceive callback, nothing to do...
  290. continue;
  291. }
  292. if (!(USISR & ( 1 << USIPF )))
  293. {
  294. // Stop not detected
  295. continue;
  296. }
  297. uint8_t amount = usiTwiAmountDataInReceiveBuffer();
  298. if (amount == 0)
  299. {
  300. // no data in buffer
  301. continue;
  302. }
  303. usi_onReceiverPtr(amount);
  304. }
  305. return 0;
  306. }