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.5KB

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