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.

main.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Note this program is designed to pair with c_client.
  2. // The i2c connection may be made directly between the two Arduino SDA and SCL pins.
  3. // No i2c pullup resistors are require.d
  4. #define F_CPU 16000000UL
  5. #define BAUD 38400
  6. #include <util/setbaud.h>
  7. #include <avr/io.h>
  8. #include <avr/interrupt.h>
  9. #include "twi.h"
  10. //------------------------------------------------------------------------------
  11. #define SER_BUF_N (16) // size of receive buffer
  12. // Note that 'ser_buf_i_idx' must be declared volatile or the
  13. // the compare in the main loop will not work.
  14. volatile int ser_buf_i_idx = 0; // receive buffer input index
  15. int ser_buf_o_idx = 0; // receive buffer output index
  16. // Receive buffer
  17. char ser_buf[ SER_BUF_N ];
  18. void uart_init(void)
  19. {
  20. UBRR0H = UBRRH_VALUE;
  21. UBRR0L = UBRRL_VALUE;
  22. #if USE_2X
  23. UCSR0A |= _BV(U2X0);
  24. #else
  25. UCSR0A &= ~(_BV(U2X0));
  26. #endif
  27. UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); // 8-bit data
  28. UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0); // Enable RX and TX and RX intertupt enable
  29. }
  30. void uart_putchar(char c)
  31. {
  32. loop_until_bit_is_set(UCSR0A, UDRE0); // Wait until data register empty.
  33. UDR0 = c;
  34. }
  35. void uart_putchar_alt(char c)
  36. {
  37. UDR0 = c;
  38. loop_until_bit_is_set(UCSR0A, TXC0); // Wait until transmission ready.
  39. }
  40. char uart_getchar(void)
  41. {
  42. loop_until_bit_is_set(UCSR0A, RXC0); // Wait until data exists.
  43. return UDR0;
  44. }
  45. //------------------------------------------------------------------------------
  46. #define I2C_LOCAL_ADDR (9)
  47. #define I2C_REMOTE_ADDR (8)
  48. #define I2C_BUF_N (16)
  49. static uint8_t i2c_buf[ I2C_BUF_N ];
  50. static volatile uint8_t i2c_buf_i_idx = 0;
  51. static uint8_t i2c_buf_o_idx = 0;
  52. static uint8_t last_char = '0';
  53. void i2c_read_from( uint8_t i2c_addr, uint8_t dev_reg_addr, uint8_t read_byte_cnt )
  54. {
  55. uint8_t recv_char = '0';
  56. const uint8_t kWaitFl = 1;
  57. const uint8_t kSendStopFl = 1;
  58. const uint8_t kNoSendStopFl = 0;
  59. // Request to read from the client. Note that 'sendStop'==0.
  60. // Use this call to tell the client what data should be sent
  61. // during the subsequent twi_readFrom().
  62. twi_writeTo(i2c_addr, &dev_reg_addr, 1, kWaitFl, kNoSendStopFl);
  63. // Blocking waiting and wait to read the client's response.
  64. for( uint8_t i=0; i<read_byte_cnt; ++i)
  65. if( twi_readFrom(i2c_addr, &recv_char, 1, i==read_byte_cnt-1) )
  66. uart_putchar(recv_char);
  67. PORTB ^= _BV(PORTB5); // toggle LED
  68. }
  69. uint8_t i2c_xmit( uint8_t remote_addr, uint8_t* buf, uint8_t n, uint8_t sendStopFl)
  70. {
  71. return twi_writeTo(remote_addr, buf, n, 1, sendStopFl);
  72. }
  73. void i2c_init()
  74. {
  75. twi_setAddress(I2C_LOCAL_ADDR);
  76. twi_init();
  77. }
  78. ISR(USART_RX_vect)
  79. {
  80. // receive the incoming byte
  81. ser_buf[ ser_buf_i_idx ] = uart_getchar();
  82. // advance the buffer input index
  83. ser_buf_i_idx = (ser_buf_i_idx + 1) % SER_BUF_N;
  84. }
  85. //--------------------------------------------------------------------------------------------------
  86. static volatile int timerFl = 0;
  87. ISR(TIMER1_COMPA_vect)
  88. {
  89. timerFl = 1;
  90. }
  91. void timer_init(void)
  92. {
  93. TCCR1A = 0; // set timer control registers to default
  94. TCCR1B = 0; //
  95. OCR1A = 15624; // 1 Hz = 16Mghz / (1024 * 15624)
  96. TCCR1B |= (1 << WGM12); // CTC mode on
  97. TCCR1B |= (1 << CS10); // Set CS10 and CS12 bits for 1024 prescaler:
  98. TCCR1B |= (1 << CS12); //
  99. TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  100. }
  101. //--------------------------------------------------------------------------------------------------
  102. int main (void)
  103. {
  104. enum { kWait_for_cmd, kWait_for_i2c, kWait_for_reg, kWait_for_cnt, kWait_for_value };
  105. const uint8_t kWaitFl = 1;
  106. const uint8_t kSendStopFl = 1;
  107. const uint8_t kNoSendStopFl = 0;
  108. const uint8_t data_bufN = 0xff;
  109. char c;
  110. uint8_t state = kWait_for_cmd; // parser state
  111. char cmd; // 'r' or 'w'
  112. uint8_t i2c_addr; // remote i2c address
  113. uint8_t dev_reg_addr; // remote device register address
  114. uint8_t op_byte_cnt; // count of data bytes to send or recv
  115. uint8_t data_buf[ data_bufN ]; // hold data during parsing
  116. uint8_t data_buf_idx = 0; // next avail slot in the data buffer
  117. cli(); // mask all interupts
  118. DDRB |= _BV(DDB5); // set led pin for output
  119. timer_init(); // setup the timer
  120. uart_init(); // setup UART data format and baud rate
  121. i2c_init();
  122. sei(); // re-enable interrupts
  123. uart_putchar('a');
  124. for(;;)
  125. {
  126. if( timerFl )
  127. {
  128. //PORTB ^= _BV(PORTB5); // toggle LED
  129. timerFl = 0;
  130. }
  131. // if there are bytes waiting in the serial buffer
  132. if( ser_buf_o_idx != ser_buf_i_idx )
  133. {
  134. // get the waiting byte
  135. c = ser_buf[ser_buf_o_idx];
  136. // advance the buffer output index
  137. ser_buf_o_idx = (ser_buf_o_idx+1) % SER_BUF_N;
  138. // Serial Protocol
  139. // 'r', i2c-addr, reg-idx, cnt, -> i2c_read_from()
  140. // 'w', i2c-addr, reg-idx, cnt, value0, ... valueN -> i2c_xmit()
  141. switch(state)
  142. {
  143. case kWait_for_cmd:
  144. if(c == 'w' || c == 'r')
  145. {
  146. cmd = c;
  147. state = kWait_for_i2c;
  148. }
  149. else
  150. uart_putchar('E'); // indicate a protocol error
  151. break;
  152. case kWait_for_i2c:
  153. i2c_addr = (uint8_t)c;
  154. state = kWait_for_reg;
  155. break;
  156. case kWait_for_reg:
  157. dev_reg_addr = (uint8_t)c;
  158. state = kWait_for_cnt;
  159. break;
  160. case kWait_for_cnt:
  161. op_byte_cnt = (uint8_t)c;
  162. if( cmd == 'r' )
  163. {
  164. i2c_read_from( i2c_addr, dev_reg_addr, op_byte_cnt );
  165. state = kWait_for_cmd;
  166. }
  167. else
  168. {
  169. // TODO: handle case where there are no data bytes (only e.g. note-off)
  170. state = kWait_for_value;
  171. data_buf[0] = dev_reg_addr; // make 'dev_reg_addr' the first data value to write
  172. data_buf_idx = 1; //
  173. op_byte_cnt += 1; // incr op_byte_cnt to account for 'dev_reg_addr' as first byte
  174. }
  175. break;
  176. case kWait_for_value:
  177. if( data_buf_idx >= data_bufN )
  178. {
  179. uart_putchar('F'); // indicate a buffer overrun
  180. state = kWait_for_cmd;
  181. }
  182. else
  183. {
  184. data_buf[ data_buf_idx++ ] = c;
  185. if(data_buf_idx == op_byte_cnt )
  186. {
  187. /*
  188. uint8_t ii;
  189. for(ii=0; ii<op_byte_cnt; ++ii)
  190. uart_putchar( data_buf[ii] );
  191. */
  192. i2c_xmit( i2c_addr, data_buf, op_byte_cnt, kSendStopFl);
  193. state = kWait_for_cmd;
  194. }
  195. }
  196. break;
  197. }
  198. }
  199. }
  200. }