Picadae hardware and control code
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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. }