i2c_slave.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /* Library made by: g4lvanix
  2. * Github repository: https://github.com/g4lvanix/I2C-slave-lib
  3. */
  4. #include <avr/io.h>
  5. #include <util/twi.h>
  6. #include <avr/interrupt.h>
  7. #include <stdbool.h>
  8. #include "i2c_slave.h"
  9. volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
  10. static volatile uint8_t buffer_address;
  11. static volatile bool slave_has_register_set = false;
  12. void i2c_slave_init(uint8_t address){
  13. // load address into TWI address register
  14. TWAR = (address << 1);
  15. // set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
  16. TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
  17. }
  18. void i2c_slave_stop(void){
  19. // clear acknowledge and enable bits
  20. TWCR &= ~((1 << TWEA) | (1 << TWEN));
  21. }
  22. ISR(TWI_vect){
  23. uint8_t ack = 1;
  24. switch(TW_STATUS){
  25. case TW_SR_SLA_ACK:
  26. // The device is now a slave receiver
  27. slave_has_register_set = false;
  28. break;
  29. case TW_SR_DATA_ACK:
  30. // This device is a slave receiver and has received data
  31. // First byte is the location then the bytes will be writen in buffer with auto-incriment
  32. if(!slave_has_register_set){
  33. buffer_address = TWDR;
  34. if (buffer_address >= I2C_SLAVE_REG_COUNT) { // address out of bounds dont ack
  35. ack = 0;
  36. buffer_address = 0;
  37. }
  38. slave_has_register_set = true; // address has been receaved now fill in buffer
  39. } else {
  40. i2c_slave_reg[buffer_address] = TWDR;
  41. buffer_address++;
  42. }
  43. break;
  44. case TW_ST_SLA_ACK:
  45. case TW_ST_DATA_ACK:
  46. // This device is a slave transmitter and master has requested data
  47. TWDR = i2c_slave_reg[buffer_address];
  48. buffer_address++;
  49. break;
  50. case TW_BUS_ERROR:
  51. // We got an error, reset i2c
  52. TWCR = 0;
  53. default:
  54. break;
  55. }
  56. // Reset i2c state machine to be ready for next interrupt
  57. TWCR |= (1 << TWIE) | (1 << TWINT) | (ack << TWEA) | (1 << TWEN);
  58. }