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.

106 lines
2.5 KiB

  1. /*
  2. Copyright 2016 Luiz Ribeiro <luizribeiro@gmail.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // Please do not modify this file
  15. #include <avr/io.h>
  16. #include <util/twi.h>
  17. #include "i2c.h"
  18. void i2c_set_bitrate(uint16_t bitrate_khz) {
  19. uint8_t bitrate_div = ((F_CPU / 1000l) / bitrate_khz);
  20. if (bitrate_div >= 16) {
  21. bitrate_div = (bitrate_div - 16) / 2;
  22. }
  23. TWBR = bitrate_div;
  24. }
  25. void i2c_init(void) {
  26. // set pull-up resistors on I2C bus pins
  27. PORTC |= 0b11;
  28. i2c_set_bitrate(400);
  29. // enable TWI (two-wire interface)
  30. TWCR |= (1 << TWEN);
  31. // enable TWI interrupt and slave address ACK
  32. TWCR |= (1 << TWIE);
  33. TWCR |= (1 << TWEA);
  34. }
  35. uint8_t i2c_start(uint8_t address) {
  36. // reset TWI control register
  37. TWCR = 0;
  38. // begin transmission and wait for it to end
  39. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
  40. while (!(TWCR & (1<<TWINT)));
  41. // check if the start condition was successfully transmitted
  42. if ((TWSR & 0xF8) != TW_START) {
  43. return 1;
  44. }
  45. // transmit address and wait
  46. TWDR = address;
  47. TWCR = (1<<TWINT) | (1<<TWEN);
  48. while (!(TWCR & (1<<TWINT)));
  49. // check if the device has acknowledged the READ / WRITE mode
  50. uint8_t twst = TW_STATUS & 0xF8;
  51. if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
  52. return 1;
  53. }
  54. return 0;
  55. }
  56. void i2c_stop(void) {
  57. TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
  58. }
  59. uint8_t i2c_write(uint8_t data) {
  60. TWDR = data;
  61. // transmit data and wait
  62. TWCR = (1<<TWINT) | (1<<TWEN);
  63. while (!(TWCR & (1<<TWINT)));
  64. if ((TWSR & 0xF8) != TW_MT_DATA_ACK) {
  65. return 1;
  66. }
  67. return 0;
  68. }
  69. uint8_t i2c_send(uint8_t address, uint8_t *data, uint16_t length) {
  70. if (i2c_start(address)) {
  71. return 1;
  72. }
  73. for (uint16_t i = 0; i < length; i++) {
  74. if (i2c_write(data[i])) {
  75. return 1;
  76. }
  77. }
  78. i2c_stop();
  79. return 0;
  80. }