greenpak.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // I2C communication with GreenPAK.
  2. // This uses bitbanging for I2C so that internal GPIO pull-up can be used
  3. // and to avoid the bugs that are present in STM32F2 I2C peripheral,
  4. // it is uncertain if the same bugs apply to GD32F2.
  5. #include "BlueSCSI_platform.h"
  6. #include "BlueSCSI_log.h"
  7. #include "greenpak.h"
  8. #include "greenpak_fw.h"
  9. #ifndef GREENPAK_I2C_PORT
  10. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length) { return false; }
  11. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length) { return false; }
  12. bool greenpak_load_firmware() { return false; }
  13. bool greenpak_is_ready() { return false; }
  14. #else
  15. bool g_greenpak_is_ready;
  16. // SCL is driven as push-pull, SDA is driven as IPU / OUT_OD
  17. #define I2C_SCL_HI() GPIO_BOP(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  18. #define I2C_SCL_LO() GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  19. #define I2C_SDA_HI() gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA)
  20. #define I2C_SDA_LO() gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_OUT_OD, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SDA), GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SDA
  21. #define I2C_SDA_READ() (GPIO_ISTAT(GREENPAK_I2C_PORT) & GREENPAK_I2C_SDA)
  22. #define I2C_DELAY() delay_ns(10000);
  23. static void greenpak_gpio_init()
  24. {
  25. gpio_bit_set(GREENPAK_I2C_PORT, GREENPAK_I2C_SCL | GREENPAK_I2C_SDA);
  26. gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA);
  27. gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SCL);
  28. // Data bits used for communication
  29. uint32_t greenpak_io = GREENPAK_PLD_IO1 | GREENPAK_PLD_IO2 | GREENPAK_PLD_IO3;
  30. gpio_bit_reset(SCSI_OUT_PORT, greenpak_io);
  31. gpio_init(SCSI_OUT_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, greenpak_io);
  32. }
  33. static void i2c_writebit(bool bit)
  34. {
  35. if (bit)
  36. I2C_SDA_HI();
  37. else
  38. I2C_SDA_LO();
  39. I2C_DELAY();
  40. I2C_SCL_HI();
  41. I2C_DELAY();
  42. I2C_SCL_LO();
  43. }
  44. static bool i2c_readbit()
  45. {
  46. I2C_SDA_HI(); // Pull-up
  47. I2C_DELAY();
  48. I2C_SCL_HI();
  49. I2C_DELAY();
  50. bool result = I2C_SDA_READ();
  51. I2C_SCL_LO();
  52. return result;
  53. }
  54. // Write byte to I2C bus, return ACK bit status
  55. static bool i2c_writebyte(uint8_t byte)
  56. {
  57. for (int i = 0; i < 8; i++)
  58. {
  59. i2c_writebit(byte & (0x80 >> i));
  60. }
  61. return !i2c_readbit();
  62. }
  63. // Read byte from I2C bus
  64. static uint8_t i2c_readbyte(bool ack)
  65. {
  66. uint8_t result = 0;
  67. for (int i = 0; i < 8; i++)
  68. {
  69. result |= i2c_readbit() << (7 - i);
  70. }
  71. i2c_writebyte(!ack);
  72. return result;
  73. }
  74. static bool i2c_start(uint8_t device_addr)
  75. {
  76. // Initial signal state
  77. I2C_SCL_HI();
  78. I2C_SDA_HI();
  79. I2C_DELAY();
  80. // Start condition
  81. I2C_SDA_LO();
  82. I2C_DELAY();
  83. I2C_SCL_LO();
  84. I2C_DELAY();
  85. // Device address
  86. return i2c_writebyte(device_addr);
  87. }
  88. static void i2c_stop()
  89. {
  90. I2C_SDA_LO();
  91. I2C_DELAY();
  92. I2C_SCL_HI();
  93. I2C_DELAY();
  94. I2C_SDA_HI();
  95. I2C_DELAY();
  96. }
  97. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length)
  98. {
  99. bool status = true;
  100. uint16_t blockaddr = regaddr >> 8;
  101. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  102. status &= i2c_writebyte(regaddr & 0xFF);
  103. for (int i = 0; i < length; i++)
  104. {
  105. status &= i2c_writebyte(data[i]);
  106. }
  107. i2c_stop();
  108. return status;
  109. }
  110. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length)
  111. {
  112. bool status = true;
  113. uint16_t blockaddr = (regaddr >> 8) & 7;
  114. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  115. status &= i2c_writebyte(regaddr & 0xFF);
  116. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1) | 1);
  117. for (int i = 0; i < length; i++)
  118. {
  119. data[i] = i2c_readbyte(i < length - 1);
  120. }
  121. i2c_stop();
  122. return status;
  123. }
  124. bool greenpak_load_firmware()
  125. {
  126. uint8_t dummy;
  127. greenpak_gpio_init();
  128. if (!greenpak_read(0, &dummy, 1))
  129. {
  130. bluelog("Optional GreenPAK not detected");
  131. return false;
  132. }
  133. else
  134. {
  135. bluelog("Optional GreenPAK detected, loading firmware");
  136. }
  137. if (!greenpak_write(0, g_greenpak_fw, sizeof(g_greenpak_fw)))
  138. {
  139. bluelog("GreenPAK firmware loading failed");
  140. return false;
  141. }
  142. else
  143. {
  144. bluelog("GreenPAK firmware successfully loaded");
  145. LED_ON();
  146. delay(10);
  147. LED_OFF();
  148. delay(100);
  149. g_greenpak_is_ready = true;
  150. return true;
  151. }
  152. }
  153. bool greenpak_is_ready()
  154. {
  155. return g_greenpak_is_ready;
  156. }
  157. #endif