Picadae hardware and control code
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

i2c_timer_pwm_2.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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 HOLD_DIR DDB3
  21. #define ATTK_DIR DDB4
  22. #define LED_DIR DDB1
  23. #define HOLD_PIN PINB3
  24. #define ATTK_PIN PINB4
  25. #define LED_PIN PINB1
  26. // Opcodes
  27. enum
  28. {
  29. kSetReg_Op = 0, // Set register <hi_addr> <lo_addr> <value0> ... <valueN>
  30. kSetPwm_Op = 1, // Set PWM registers <enable> <duty> <freq>
  31. kNoteOnVel_Op = 2, // Turn on note <vel>
  32. kNoteOnUsec_Op = 3, // Turn on note <coarse> <fine>
  33. kNoteOff_Op = 4, // Turn off note
  34. kRead_Op = 5, // Read a value {{ <src>} <addr> }
  35. kInvalid_Op = 6
  36. };
  37. // Register addresses
  38. enum
  39. {
  40. kTmr_Coarse_idx = 0, // Current Timer 0 coarse count
  41. kTmr_Fine_idx = 1, // Current Timer 0 fine count
  42. kTmr_Prescale_idx = 2, // Current Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
  43. kPwm_Enable_idx = 3, // Current PWM 1 enable flag
  44. kPwm_Duty_idx = 4, // Current PWM 1 duty cycle
  45. kPwm_Freq_idx = 5, // Current PWM 1 frequency
  46. kRead_Src_idx = 6, // 0=reg, 1=table, 2=eeprom
  47. kReg_Addr_idx = 7, // Next Reg Address to read
  48. kTable_Addr_idx = 8, // Next Table Address to read
  49. kEE_Addr_idx = 9, // Next EEPROM address to read
  50. kError_Code_idx = 10, // Error Code
  51. kMax_idx
  52. };
  53. // Regster memory
  54. volatile uint8_t ctl_regs[] =
  55. {
  56. 123, // 1 (0-255) Timer 0 Coarse Value
  57. 8, // 2 (0-255) Timer 0 Fine Value
  58. 4, // 0 (1-5) 4=32us per tick
  59. 1, // 5 (0-1) PWM1 Enable
  60. 127, // 3 (0-255) PWM1 Duty cycle (0-100%)
  61. 254, // 4 (0-255) PWM1 Frequency (123 hz)
  62. 0, // 6 (0-255) Read Source
  63. 0, // 7 (0-255) Reg addr
  64. 0, // 8 (0-255) Table addr
  65. 0, // 9 (0-255) EEPROM addr
  66. 0, // 10 (0-255) Error code
  67. };
  68. volatile uint8_t table[128];
  69. #define stackN 16
  70. volatile uint8_t stack[ stackN ];
  71. //------------------------------------------------------------------------------
  72. //------------------------------------------------------------------------------
  73. //------------------------------------------------------------------------------
  74. //
  75. // EEPROM
  76. //
  77. void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
  78. {
  79. // Wait for completion of previous write
  80. while(EECR & (1<<EEPE))
  81. {}
  82. EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode
  83. EEARH = 0; // Set up address and data registers
  84. EEARL = ucAddress;
  85. EEDR = ucData;
  86. EECR |= (1<<EEMPE); // Write logical one to EEMPE
  87. EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
  88. }
  89. uint8_t EEPROM_read(uint8_t ucAddress)
  90. {
  91. // Wait for completion of previous write
  92. while(EECR & (1<<EEPE))
  93. {}
  94. EEARH = 0; // Set up address and data registers
  95. EEARL = ucAddress;
  96. EECR |= (1<<EERE); // Start eeprom read by writing EERE
  97. return EEDR; // Return data from data register
  98. }
  99. //------------------------------------------------------------------------------
  100. //------------------------------------------------------------------------------
  101. //------------------------------------------------------------------------------
  102. //
  103. // Read/Write table
  104. //
  105. #define eeprom_addr( addr ) (addr)
  106. void table_load( void )
  107. {
  108. uint8_t i = 0;
  109. for(; i<64; ++i)
  110. {
  111. uint16_t tbl_addr = i*2;
  112. table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
  113. table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
  114. }
  115. }
  116. void restore_memory_from_eeprom( void )
  117. {
  118. /*
  119. uint8_t i;
  120. for(i=0; i<kMax_idx; ++i)
  121. {
  122. ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
  123. }
  124. */
  125. table_load();
  126. }
  127. //------------------------------------------------------------------------------
  128. //------------------------------------------------------------------------------
  129. //------------------------------------------------------------------------------
  130. //
  131. // Timer0
  132. //
  133. volatile uint8_t tmr0_state = 0; // 0=disabled 1=coarse mode, 2=fine mode
  134. volatile uint8_t tmr0_coarse_cur = 0;
  135. // Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
  136. void tmr0_reset()
  137. {
  138. // if a coarse count exists then go into coarse mode
  139. if( ctl_regs[kTmr_Coarse_idx] > 0 )
  140. {
  141. tmr0_state = 1;
  142. OCR0A = 0xff;
  143. }
  144. else // otherwise go into fine mode
  145. {
  146. tmr0_state = 2;
  147. OCR0A = ctl_regs[kTmr_Fine_idx];
  148. }
  149. tmr0_coarse_cur = 0;
  150. }
  151. ISR(TIMER0_COMPA_vect)
  152. {
  153. switch( tmr0_state )
  154. {
  155. case 0:
  156. // disabled
  157. break;
  158. case 1:
  159. // coarse mode
  160. if( ++tmr0_coarse_cur >= ctl_regs[kTmr_Coarse_idx] )
  161. {
  162. tmr0_state = 2;
  163. OCR0A = ctl_regs[kTmr_Fine_idx];
  164. }
  165. break;
  166. case 2:
  167. // fine mode
  168. PINB = _BV(ATTK_PIN); // writes to PINB toggle the pins
  169. tmr0_reset(); // restart the timer
  170. break;
  171. }
  172. }
  173. void timer0_init()
  174. {
  175. TIMSK &= ~_BV(OCIE0A); // Disable interrupt TIMER0_COMPA_vect
  176. TCCR0A |= 0x02; // CTC mode
  177. TCCR0B |= ctl_regs[kTmr_Prescale_idx]; // set the prescaler
  178. GTCCR |= _BV(PSR0); // Set the pre-scaler to the selected value
  179. tmr0_reset(); // set the timers starting state
  180. TIMSK |= _BV(OCIE0A); // Enable interrupt TIMER0_COMPA_vect
  181. }
  182. //------------------------------------------------------------------------------
  183. //------------------------------------------------------------------------------
  184. //------------------------------------------------------------------------------
  185. //
  186. // PWM1
  187. //
  188. // PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
  189. // but since these pins are not available this code uses
  190. // ISR's to redirect the output to PIN3
  191. void pwm1_update()
  192. {
  193. OCR1B = ctl_regs[kPwm_Duty_idx]; // control duty cycle
  194. OCR1C = ctl_regs[kPwm_Freq_idx]; // PWM frequency pre-scaler
  195. }
  196. ISR(TIMER1_OVF_vect)
  197. {
  198. PORTB |= _BV(HOLD_PIN); // set PWM pin
  199. }
  200. ISR(TIMER1_COMPB_vect)
  201. {
  202. PORTB &= ~(_BV(HOLD_PIN)); // clear PWM pin
  203. }
  204. void pwm1_init()
  205. {
  206. TIMSK &= ~(_BV(OCIE1B) + _BV(TOIE1)); // Disable interrupts
  207. DDRB |= _BV(HOLD_DIR); // setup PB3 as output
  208. // set on TCNT1 == 0 // happens when TCNT1 matches OCR1C
  209. // clr on OCR1B == TCNT // happens when TCNT1 matches OCR1B
  210. // // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
  211. TCCR1 |= 9; // 32us period (256 divider) prescaler
  212. GTCCR |= _BV(PWM1B); // Enable PWM B and disconnect output pins
  213. GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
  214. pwm1_update();
  215. TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // Enable interrupts
  216. }
  217. //------------------------------------------------------------------------------
  218. //------------------------------------------------------------------------------
  219. //------------------------------------------------------------------------------
  220. //
  221. // Read Request Handler
  222. //
  223. // This is called for each read request we receive, never put more
  224. // than one byte of data (with TinyWireS.send) to the send-buffer when
  225. // using this callback
  226. //
  227. void on_request()
  228. {
  229. uint8_t val = 0;
  230. switch( ctl_regs[ kRead_Src_idx ] )
  231. {
  232. case 0:
  233. val = table[ ctl_regs[ kReg_Addr_idx ] ];
  234. ctl_regs[ kReg_Addr_idx ] += 1;
  235. break;
  236. case 1:
  237. val = table[ ctl_regs[ kTable_Addr_idx ] ];
  238. ctl_regs[ kTable_Addr_idx ] += 1;
  239. break;
  240. case 2:
  241. val = EEPROM_read(ctl_regs[ kEE_Addr_idx]);
  242. ctl_regs[ kEE_Addr_idx ] += 1;
  243. }
  244. usiTwiTransmitByte(val);
  245. }
  246. //
  247. // The I2C data received -handler
  248. //
  249. // This needs to complete before the next incoming transaction (start,
  250. // data, restart/stop) on the bus does so be quick, set flags for long
  251. // running tasks to be called from the mainloop instead of running
  252. // them directly,
  253. //
  254. void on_receive( uint8_t byteN )
  255. {
  256. uint8_t stack_idx = 0;
  257. PINB = _BV(LED_PIN); // writes to PINB toggle the pins
  258. // Sanity-check
  259. if( byteN < 1 || byteN > TWI_RX_BUFFER_SIZE)
  260. {
  261. // TODO: signal an error
  262. return;
  263. }
  264. // get the command byte
  265. uint8_t cur_op_id = usiTwiReceiveByte();
  266. --byteN;
  267. // verify that cur_op_id is valid
  268. if( cur_op_id < kInvalid_Op )
  269. {
  270. // TODO: signal an error
  271. return;
  272. }
  273. // get the command arguments
  274. while(byteN--)
  275. {
  276. // write the value
  277. stack[stack_idx] = usiTwiReceiveByte();
  278. ++stack_idx;
  279. if(stack_idx >= stackN)
  280. {
  281. // TODO: signal an error
  282. break;
  283. }
  284. }
  285. // execute the operation
  286. switch( cur_op_id )
  287. {
  288. case kSetReg_Op: // Set register <reg> <value0> ... <valueN>
  289. if( stack_idx > 1 )
  290. {
  291. uint8_t addr = stack[0];
  292. uint8_t i = 2;
  293. for(; i<stack_idx; ++i,++addr)
  294. ctl_regs[ addr ] = stack[i];
  295. }
  296. break;
  297. case kSetPwm_Op: // Set pwm <enable>,<duty>,<freq>
  298. {
  299. uint8_t addr = kPwm_Enable_idx;
  300. uint8_t i = 0;
  301. for(; i<stack_idx; ++i,++addr)
  302. ctl_regs[ addr ] = stack[i];
  303. pwm1_update();
  304. }
  305. break;
  306. case kNoteOnVel_Op: // Turn on note <vel>
  307. if( stack_idx == 1 )
  308. {
  309. uint8_t addr = stack[0] >> 2; // divide by 2 (we have only 64 entries in the table)
  310. ctl_regs[ kTmr_Coarse_idx ] = table[ addr ];
  311. ctl_regs[ kTmr_Fine_idx ] = table[ addr+1 ];
  312. }
  313. tmr0_reset();
  314. break;
  315. case kNoteOnUsec_Op: // Turn on note <coarse> <fine>
  316. if( stack_idx == 2 )
  317. {
  318. ctl_regs[ kTmr_Coarse_idx ] = stack[0];
  319. ctl_regs[ kTmr_Fine_idx ] = stack[1];
  320. }
  321. tmr0_reset();
  322. break;
  323. case kNoteOff_Op: // Turn off note
  324. PORTB &= ~(_BV(ATTK_PIN) + _BV(HOLD_PIN));
  325. break;
  326. case kRead_Op: // Read a value {{ <src>} <addr> }
  327. if( stack_idx > 0)
  328. {
  329. ctl_regs[ kRead_Src_idx ] = stack[0];
  330. }
  331. if( stack_idx > 1 )
  332. {
  333. uint8_t reg_addr = 4;
  334. switch( ctl_regs[ kRead_Src_idx ] )
  335. {
  336. case 0: reg_addr = kReg_Addr_idx; break;
  337. case 1: reg_addr = kTable_Addr_idx; break;
  338. case 2: reg_addr = kEE_Addr_idx; break;
  339. default:
  340. // TODO: signal error
  341. break;
  342. }
  343. if( reg_addr <= 2 )
  344. ctl_regs[ reg_addr ] = stack[1];
  345. }
  346. }
  347. }
  348. int main(void)
  349. {
  350. cli(); // mask all interupts
  351. DDRB |= _BV(ATTK_DIR) + _BV(HOLD_DIR) + _BV(LED_DIR); // setup PB4,PB3,PB1 as output
  352. PORTB &= ~(_BV(ATTK_PIN) + _BV(HOLD_PIN) + _BV(LED_PIN)); // clear output pins
  353. timer0_init();
  354. pwm1_init();
  355. // setup i2c library
  356. usi_onReceiverPtr = on_receive;
  357. usi_onRequestPtr = on_request;
  358. usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
  359. sei();
  360. PINB = _BV(LED_PIN); // writes to PINB toggle the pins
  361. _delay_ms(1000);
  362. PINB = _BV(LED_PIN); // writes to PINB toggle the pins
  363. while(1)
  364. {
  365. //_delay_ms(1000);
  366. if (!usi_onReceiverPtr)
  367. {
  368. // no onReceive callback, nothing to do...
  369. continue;
  370. }
  371. if (!(USISR & ( 1 << USIPF )))
  372. {
  373. // Stop not detected
  374. continue;
  375. }
  376. uint8_t amount = usiTwiAmountDataInReceiveBuffer();
  377. if (amount == 0)
  378. {
  379. // no data in buffer
  380. continue;
  381. }
  382. usi_onReceiverPtr(amount);
  383. }
  384. return 0;
  385. }