Picadae hardware and control code
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

i2c_timer_pwm_1a.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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. enum
  21. {
  22. kTmr0_Prescale_idx = 0, // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
  23. kTmr0_Coarse_idx = 1, //
  24. kTmr0_Fine_idx = 2, //
  25. kPWM1_Duty_idx = 3, //
  26. kPWM1_Freq_idx = 4, //
  27. kTable_Addr_idx = 5, // Next table address to read/write
  28. kTable_Coarse_idx = 6, // Next table coarse value to read/write
  29. kTable_Fine_idx = 7, // Next table fine value to read/write
  30. kMax_idx
  31. };
  32. volatile uint8_t ctl_regs[] =
  33. {
  34. 4, // 0 (1-5) 4=32us per tick
  35. 123, // 1 (0-255) Timer 0 Coarse Value
  36. 8, // 2 (0-255) Timer 0 Fine Value
  37. 127, // 3 (0-255) PWM1 Duty cycle
  38. 254, // 4 (0-255) PWM1 Frequency (123 hz)
  39. 0, // 5 (0-127) Next table addr to read/write
  40. 0, // 6 (0-255) Next table coarse value to write
  41. 0, // 7 (0-255) Next table fine value to write
  42. };
  43. #define tableN 256
  44. uint8_t table[ tableN ];
  45. //------------------------------------------------------------------------------
  46. //------------------------------------------------------------------------------
  47. //------------------------------------------------------------------------------
  48. //
  49. // EEPROM
  50. //
  51. void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
  52. {
  53. // Wait for completion of previous write
  54. while(EECR & (1<<EEPE))
  55. {}
  56. EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode
  57. EEAR = ucAddress; // Set up address and data registers
  58. EEDR = ucData;
  59. EECR |= (1<<EEMPE); // Write logical one to EEMPE
  60. EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
  61. }
  62. uint8_t EEPROM_read(uint8_t ucAddress)
  63. {
  64. // Wait for completion of previous write
  65. while(EECR & (1<<EEPE))
  66. {}
  67. EEAR = ucAddress; // Set up address register
  68. EECR |= (1<<EERE); // Start eeprom read by writing EERE
  69. return EEDR; // Return data from data register
  70. }
  71. //------------------------------------------------------------------------------
  72. //------------------------------------------------------------------------------
  73. //------------------------------------------------------------------------------
  74. //
  75. // Read/Write table
  76. //
  77. // To write table value 42 to 127 (coarse) 64 (fine)
  78. //
  79. // w 8 kTable_Addr_idx 42
  80. // w 8 kTable_Coarse_idx 127
  81. // w 8 kTable_fine_idx 64
  82. //
  83. // TO read table value 42
  84. // w 8 kTable_Addr_idx 42
  85. // r 8 kTable_Coarse_idx -> 127
  86. // r 8 kTable_Fine_idx -> 64
  87. #define eeprom_addr( addr ) (kMax_idx + (addr))
  88. void table_write_cur_value( void )
  89. {
  90. uint8_t tbl_addr = ctl_regs[ kTable_Addr_idx ] * 2;
  91. table[ tbl_addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
  92. table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ];
  93. EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
  94. EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]);
  95. }
  96. void table_load( void )
  97. {
  98. uint8_t i = 0;
  99. for(; i<128; ++i)
  100. {
  101. uint8_t tbl_addr = i*2;
  102. table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
  103. table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
  104. }
  105. }
  106. void restore_memory_from_eeprom( void )
  107. {
  108. /*
  109. uint8_t i;
  110. for(i=0; i<kMax_idx; ++i)
  111. {
  112. ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
  113. }
  114. */
  115. table_load();
  116. }
  117. //------------------------------------------------------------------------------
  118. //------------------------------------------------------------------------------
  119. //------------------------------------------------------------------------------
  120. //
  121. // Timer0
  122. //
  123. volatile uint8_t tmr0_state = 0; // 0=disabled 1=coarse mode, 2=fine mode
  124. volatile uint8_t tmr0_coarse_cur = 0;
  125. // Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
  126. void tmr0_reset()
  127. {
  128. // if a coarse count exists then go into coarse mode
  129. if( ctl_regs[kTmr0_Coarse_idx] > 0 )
  130. {
  131. tmr0_state = 1;
  132. OCR0A = 0xff;
  133. }
  134. else // otherwise go into fine mode
  135. {
  136. tmr0_state = 2;
  137. OCR0A = ctl_regs[kTmr0_Fine_idx];
  138. }
  139. tmr0_coarse_cur = 0;
  140. }
  141. ISR(TIMER0_COMPA_vect)
  142. {
  143. switch( tmr0_state )
  144. {
  145. case 0:
  146. // disabled
  147. break;
  148. case 1:
  149. // coarse mode
  150. if( ++tmr0_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
  151. {
  152. tmr0_state = 2;
  153. OCR0A = ctl_regs[kTmr0_Fine_idx];
  154. }
  155. break;
  156. case 2:
  157. // fine mode
  158. PINB = _BV(PINB4); // writes to PINB toggle the pins
  159. tmr0_reset(); // restart the timer
  160. break;
  161. }
  162. }
  163. void timer0_init()
  164. {
  165. TIMSK &= ~_BV(OCIE0A); // Disable interrupt TIMER1_OVF
  166. TCCR0A |= 0x02; // CTC mode
  167. TCCR0B |= ctl_regs[kTmr0_Prescale_idx]; // set the prescaler
  168. GTCCR |= _BV(PSR0); // Set the pre-scaler to the selected value
  169. tmr0_reset(); // set the timers starting state
  170. TIMSK |= _BV(OCIE0A); // Enable interrupt TIMER1_OVF
  171. }
  172. //------------------------------------------------------------------------------
  173. //------------------------------------------------------------------------------
  174. //------------------------------------------------------------------------------
  175. //
  176. // PWM1
  177. //
  178. // PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
  179. // but since these pins are not available this code uses
  180. // ISR's to redirect the output to PIN3
  181. void pwm1_update()
  182. {
  183. OCR1B = ctl_regs[kPWM1_Duty_idx]; // control duty cycle
  184. OCR1C = ctl_regs[kPWM1_Freq_idx]; // PWM frequency pre-scaler
  185. }
  186. ISR(TIMER1_OVF_vect)
  187. {
  188. PORTB |= _BV(PINB3); // set PWM pin
  189. }
  190. ISR(TIMER1_COMPB_vect)
  191. {
  192. PORTB &= ~(_BV(PINB3)); // clear PWM pin
  193. }
  194. void pwm1_init()
  195. {
  196. TIMSK &= ~(_BV(OCIE1B) + _BV(TOIE1)); // Disable interrupts
  197. DDRB |= _BV(DDB3); // setup PB3 as output
  198. // set on TCNT1 == 0 // happens when TCNT1 matches OCR1C
  199. // clr on OCR1B == TCNT // happens when TCNT1 matches OCR1B
  200. // // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
  201. TCCR1 |= 9; // 32us period (256 divider) prescaler
  202. GTCCR |= _BV(PWM1B); // Enable PWM B and disconnect output pins
  203. GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
  204. pwm1_update();
  205. TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // Enable interrupts
  206. }
  207. //------------------------------------------------------------------------------
  208. //------------------------------------------------------------------------------
  209. //------------------------------------------------------------------------------
  210. // Tracks the current register pointer position
  211. volatile uint8_t reg_position = 0;
  212. const uint8_t reg_size = sizeof(ctl_regs);
  213. //
  214. // Read Request Handler
  215. //
  216. // This is called for each read request we receive, never put more
  217. // than one byte of data (with TinyWireS.send) to the send-buffer when
  218. // using this callback
  219. //
  220. void on_request()
  221. {
  222. uint8_t val = 0;
  223. switch( reg_position )
  224. {
  225. case kTable_Coarse_idx:
  226. val = table[ ctl_regs[kTable_Addr_idx]*2 + 0 ];
  227. break;
  228. case kTable_Fine_idx:
  229. val = table[ ctl_regs[kTable_Addr_idx]*2 + 1 ];
  230. break;
  231. default:
  232. // read and transmit the requestd position
  233. val = ctl_regs[reg_position];
  234. }
  235. usiTwiTransmitByte(val);
  236. // Increment the reg position on each read, and loop back to zero
  237. reg_position++;
  238. if (reg_position >= reg_size)
  239. {
  240. reg_position = 0;
  241. }
  242. }
  243. //
  244. // The I2C data received -handler
  245. //
  246. // This needs to complete before the next incoming transaction (start,
  247. // data, restart/stop) on the bus does so be quick, set flags for long
  248. // running tasks to be called from the mainloop instead of running
  249. // them directly,
  250. //
  251. void on_receive( uint8_t byteN )
  252. {
  253. PINB = _BV(PINB1); // writes to PINB toggle the pins
  254. if (byteN < 1)
  255. {
  256. // Sanity-check
  257. return;
  258. }
  259. if (byteN > TWI_RX_BUFFER_SIZE)
  260. {
  261. // Also insane number
  262. return;
  263. }
  264. // get the register index to read/write
  265. reg_position = usiTwiReceiveByte();
  266. byteN--;
  267. // If only one byte was received then this was a read request
  268. // and the buffer pointer (reg_position) is now set to return the byte
  269. // at this location on the subsequent call to on_request() ...
  270. if (!byteN)
  271. {
  272. return;
  273. }
  274. // ... otherwise this was a write request and the buffer
  275. // pointer is now pointing to the first byte to write to
  276. while(byteN--)
  277. {
  278. // write the value
  279. ctl_regs[reg_position] = usiTwiReceiveByte();
  280. // Set timer 1
  281. if( kTmr0_Prescale_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
  282. { timer0_init(); }
  283. else
  284. // Set PWM 1
  285. if( kPWM1_Duty_idx <= reg_position && reg_position <= kPWM1_Freq_idx )
  286. { pwm1_update(); }
  287. else
  288. // Write table
  289. if( reg_position == kTable_Fine_idx )
  290. { table_write_cur_value(); }
  291. reg_position++;
  292. if (reg_position >= reg_size)
  293. {
  294. reg_position = 0;
  295. }
  296. }
  297. }
  298. int main(void)
  299. {
  300. cli(); // mask all interupts
  301. restore_memory_from_eeprom();
  302. DDRB |= _BV(DDB4) + _BV(DDB3) + _BV(DDB1); // setup PB4,PB3,PB1 as output
  303. PORTB &= ~(_BV(PINB4) + _BV(PINB3) + _BV(PINB1)); // clear output pins
  304. timer0_init();
  305. pwm1_init();
  306. // setup i2c library
  307. usi_onReceiverPtr = on_receive;
  308. usi_onRequestPtr = on_request;
  309. usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
  310. sei();
  311. PINB = _BV(PINB1); // writes to PINB toggle the pins
  312. _delay_ms(1000);
  313. PINB = _BV(PINB1); // writes to PINB toggle the pins
  314. while(1)
  315. {
  316. //_delay_ms(1000);
  317. if (!usi_onReceiverPtr)
  318. {
  319. // no onReceive callback, nothing to do...
  320. continue;
  321. }
  322. if (!(USISR & ( 1 << USIPF )))
  323. {
  324. // Stop not detected
  325. continue;
  326. }
  327. uint8_t amount = usiTwiAmountDataInReceiveBuffer();
  328. if (amount == 0)
  329. {
  330. // no data in buffer
  331. continue;
  332. }
  333. usi_onReceiverPtr(amount);
  334. }
  335. return 0;
  336. }