eeprom_i2c.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * eeprom_i2c.c
  3. *
  4. * Copyright 2022 dh33ex <dh33ex@riseup.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301, USA or see <http://www.gnu.org/licenses/>.
  20. *
  21. *
  22. */
  23. #ifndef __msp430_h_
  24. #include <msp430.h>
  25. #endif
  26. #include "eeprom_i2c.h"
  27. int ptr_buf;
  28. char i2c_buffer[68];
  29. void EEPROM_init(unsigned char i2c_address) {
  30. /* setup B0 for I2C */
  31. UCB0CTL1 |= UCSWRST; /* put B0 in SW RST */
  32. UCB0CTL1 |= UCSSEL_2; /* choose SMCLK */
  33. UCB0BR0 = 10; /* set presalar to 10 */
  34. UCB0BR1 = 0;
  35. UCB0CTL0 |= UCMODE_3; /* put into I2C mode */
  36. UCB0CTL0 |= UCMST; /* set as master */
  37. UCB0I2CSA = i2c_address; /* set slave address */
  38. /* setup ports */
  39. P1SEL |= BIT7; /* P1.7 = SDA */
  40. P1SEL2 |= BIT7;
  41. P1SEL |= BIT6; /* P1.6 = SCL */
  42. P1SEL2 |= BIT6;
  43. UCB0CTL1 &= ~UCSWRST; /* take B0 out of SW RST */
  44. }
  45. void EEPROM_write_setup(void) {
  46. UCB0CTL1 |= UCTR; /* set transmit mode */
  47. IFG2 &= ~UCB0TXIFG; /* clear transmit interrupt flag */
  48. IE2 &= ~UCB0RXIE; /* disable recive interrupt */
  49. IE2 |= UCB0TXIE; /* enable transmit interrupt */
  50. }
  51. void EEPROM_read_setup(void) {
  52. UCB0CTL1 &= ~UCTR; /* set recive mode */
  53. IFG2 &= ~UCB0RXIFG; /* clear recive interrupt flag */
  54. IE2 &= ~UCB0TXIE; /* disable transmit interrupt */
  55. IE2 |= UCB0RXIE; /* enable receive interrupt */
  56. }
  57. void EEPROM_ACK_polling(void) {
  58. while (UCB0STAT & UCBUSY); /* wait until I2C is free */
  59. UCB0CTL1 |= UCTR; /* set transmit mode */
  60. do {
  61. UCB0STAT &= ~UCNACKIFG; /* clear NACK flag */
  62. UCB0CTL1 |= UCTXSTT; /* send start message manually */
  63. while (UCB0CTL1 & UCTXSTT) { /* wait until start message sent */
  64. if (!(UCB0STAT & UCNACKIFG)) { /* break if ACK recived */
  65. break;
  66. }
  67. }
  68. UCB0CTL1 |= UCTXSTP; /* send stop message manually */
  69. while (UCB0CTL1 & UCTXSTP); /* wait until stop message sent */
  70. } while (UCB0STAT & UCNACKIFG); /* wait until ACK recived */
  71. }
  72. void EEPROM_sequential_read(unsigned char size, unsigned short addr, unsigned char *buffer) {
  73. while (UCB0STAT & UCBUSY); /* wait until I2C is free */
  74. i2c_buffer[1] = addr >> 8; /* save high byte */
  75. i2c_buffer[0] = addr & 0xFF; /* save low byte */
  76. ptr_buf = 1; /* set pointer */
  77. EEPROM_write_setup(); /* setup to write operation */
  78. UCB0CTL1 |= UCTXSTT; /* send start message manually */
  79. __bis_SR_register(LPM0_bits + GIE); /* enter interrupt w/ LP0 */
  80. EEPROM_read_setup(); /* setup to read operation */
  81. UCB0CTL1 |= UCTXSTT; /* send start message manually */
  82. while (UCB0CTL1 & UCTXSTT); /* wait until start message sent */
  83. /* read bytes excluding the last one */
  84. unsigned short cnt_size;
  85. for (cnt_size = 0 ; cnt_size < size - 1; cnt_size++) {
  86. __bis_SR_register(LPM0_bits + GIE); /* enter interrupt w/ LP0 */
  87. buffer[cnt_size] = i2c_buffer[0]; /* read byte */
  88. }
  89. /* send stop message and read last byte */
  90. UCB0CTL1 |= UCTXSTP; /* send stop message manually */
  91. __bis_SR_register(LPM0_bits + GIE); /* enter interrupt w/ LP0 */
  92. while (UCB0CTL1 & UCTXSTP); /* wait until stop message sent */
  93. buffer[cnt_size] = i2c_buffer[0]; /* read byte */
  94. }
  95. void EEPROM_page_write(unsigned char size, unsigned short addr, unsigned char *buffer, unsigned char ack) {
  96. while (UCB0STAT & UCBUSY); /* wait until I2C is free */
  97. i2c_buffer[size + 1] = addr >> 8; /* save high byte */
  98. i2c_buffer[size] = addr & 0xFF; /* save low byte */
  99. ptr_buf = size + 1; /* set pointer */
  100. unsigned short cnt_size;
  101. for (cnt_size = 0; cnt_size < size; cnt_size++) {
  102. i2c_buffer[size-cnt_size - 1] = buffer[cnt_size];
  103. }
  104. EEPROM_write_setup(); /* setup to write operation */
  105. UCB0CTL1 |= UCTXSTT; /* send start message manually */
  106. __bis_SR_register(LPM0_bits + GIE); /* enter interrupt w/ LP0 */
  107. UCB0CTL1 |= UCTXSTP; /* send stop message manually */
  108. while (UCB0CTL1 & UCTXSTP); /* wait until stop message sent */
  109. if (ack) {
  110. EEPROM_ACK_polling(); /* determine end data write cycle using ACK polling */
  111. } else {
  112. __delay_cycles(5000); /* wait 5ms (1 Mhz) */
  113. }
  114. }
  115. /*---- ISR ----*/
  116. #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
  117. #pragma vector = USCIAB0TX_VECTOR
  118. __interrupt void USCIAB0TX_I2C_ISR(void) {
  119. #elif defined(__GNUC__)
  120. void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_I2C_ISR (void) {
  121. #else
  122. #error Compiler not supported!
  123. #endif
  124. if (UCB0TXIFG & IFG2) {
  125. UCB0TXBUF = i2c_buffer[ptr_buf]; /* Load TX buffer */
  126. ptr_buf--; /* Decrement TX byte counter */
  127. if (ptr_buf < 0) {
  128. while (!(IFG2 & UCB0TXIFG));
  129. IE2 &= ~UCB0TXIE; /* disable interrupts */
  130. IFG2 &= ~UCB0TXIFG; /* Clear USCI_B0 TX int flag */
  131. __bic_SR_register_on_exit(LPM0_bits); /* Exit LPM0 */
  132. }
  133. } else if (UCB0RXIFG & IFG2) {
  134. i2c_buffer[0] = UCB0RXBUF; /* store received data in buffer */
  135. __bic_SR_register_on_exit(LPM0_bits); /* Exit LPM0 */
  136. }
  137. }