greenpak.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2022-2025 Rabbit Hole Computing™
  3. *
  4. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  5. *
  6. * https://www.gnu.org/licenses/gpl-3.0.html
  7. * ----
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version. 
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. * GNU General Public License for more details. 
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  20. **/
  21. // I2C communication with GreenPAK.
  22. // This uses bitbanging for I2C so that internal GPIO pull-up can be used
  23. // and to avoid the bugs that are present in STM32F2 I2C peripheral,
  24. // it is uncertain if the same bugs apply to GD32F2.
  25. #include "ZuluSCSI_platform.h"
  26. #include "ZuluSCSI_log.h"
  27. #include "greenpak.h"
  28. #include "greenpak_fw.h"
  29. #ifndef GREENPAK_I2C_PORT
  30. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length) { return false; }
  31. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length) { return false; }
  32. bool greenpak_load_firmware() { return false; }
  33. bool greenpak_is_ready() { return false; }
  34. #else
  35. bool g_greenpak_is_ready;
  36. // SCL is driven as push-pull, SDA is driven as IPU / OUT_OD
  37. #define I2C_SCL_HI() GPIO_BOP(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  38. #define I2C_SCL_LO() GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  39. #define I2C_SDA_HI() gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA)
  40. #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
  41. #define I2C_SDA_READ() (GPIO_ISTAT(GREENPAK_I2C_PORT) & GREENPAK_I2C_SDA)
  42. #define I2C_DELAY() delay_ns(10000);
  43. static void greenpak_gpio_init()
  44. {
  45. gpio_bit_set(GREENPAK_I2C_PORT, GREENPAK_I2C_SCL | GREENPAK_I2C_SDA);
  46. gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA);
  47. gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SCL);
  48. // Data bits used for communication
  49. uint32_t greenpak_io = GREENPAK_PLD_IO1 | GREENPAK_PLD_IO2 | GREENPAK_PLD_IO3;
  50. gpio_bit_reset(SCSI_OUT_PORT, greenpak_io);
  51. gpio_init(SCSI_OUT_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, greenpak_io);
  52. }
  53. static void i2c_writebit(bool bit)
  54. {
  55. if (bit)
  56. I2C_SDA_HI();
  57. else
  58. I2C_SDA_LO();
  59. I2C_DELAY();
  60. I2C_SCL_HI();
  61. I2C_DELAY();
  62. I2C_SCL_LO();
  63. }
  64. static bool i2c_readbit()
  65. {
  66. I2C_SDA_HI(); // Pull-up
  67. I2C_DELAY();
  68. I2C_SCL_HI();
  69. I2C_DELAY();
  70. bool result = I2C_SDA_READ();
  71. I2C_SCL_LO();
  72. return result;
  73. }
  74. // Write byte to I2C bus, return ACK bit status
  75. static bool i2c_writebyte(uint8_t byte)
  76. {
  77. for (int i = 0; i < 8; i++)
  78. {
  79. i2c_writebit(byte & (0x80 >> i));
  80. }
  81. return !i2c_readbit();
  82. }
  83. // Read byte from I2C bus
  84. static uint8_t i2c_readbyte(bool ack)
  85. {
  86. uint8_t result = 0;
  87. for (int i = 0; i < 8; i++)
  88. {
  89. result |= i2c_readbit() << (7 - i);
  90. }
  91. i2c_writebyte(!ack);
  92. return result;
  93. }
  94. static bool i2c_start(uint8_t device_addr)
  95. {
  96. // Initial signal state
  97. I2C_SCL_HI();
  98. I2C_SDA_HI();
  99. I2C_DELAY();
  100. // Start condition
  101. I2C_SDA_LO();
  102. I2C_DELAY();
  103. I2C_SCL_LO();
  104. I2C_DELAY();
  105. // Device address
  106. return i2c_writebyte(device_addr);
  107. }
  108. static void i2c_stop()
  109. {
  110. I2C_SDA_LO();
  111. I2C_DELAY();
  112. I2C_SCL_HI();
  113. I2C_DELAY();
  114. I2C_SDA_HI();
  115. I2C_DELAY();
  116. }
  117. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length)
  118. {
  119. bool status = true;
  120. uint16_t blockaddr = regaddr >> 8;
  121. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  122. status &= i2c_writebyte(regaddr & 0xFF);
  123. for (int i = 0; i < length; i++)
  124. {
  125. status &= i2c_writebyte(data[i]);
  126. }
  127. i2c_stop();
  128. return status;
  129. }
  130. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length)
  131. {
  132. bool status = true;
  133. uint16_t blockaddr = (regaddr >> 8) & 7;
  134. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  135. status &= i2c_writebyte(regaddr & 0xFF);
  136. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1) | 1);
  137. for (int i = 0; i < length; i++)
  138. {
  139. data[i] = i2c_readbyte(i < length - 1);
  140. }
  141. i2c_stop();
  142. return status;
  143. }
  144. bool greenpak_load_firmware()
  145. {
  146. uint8_t dummy;
  147. greenpak_gpio_init();
  148. if (!greenpak_read(0, &dummy, 1))
  149. {
  150. logmsg("Optional GreenPAK not detected");
  151. return false;
  152. }
  153. else
  154. {
  155. logmsg("Optional GreenPAK detected, loading firmware");
  156. }
  157. if (!greenpak_write(0, g_greenpak_fw, sizeof(g_greenpak_fw)))
  158. {
  159. logmsg("GreenPAK firmware loading failed");
  160. return false;
  161. }
  162. else
  163. {
  164. logmsg("GreenPAK firmware successfully loaded");
  165. LED_ON();
  166. delay(10);
  167. LED_OFF();
  168. delay(100);
  169. g_greenpak_is_ready = true;
  170. return true;
  171. }
  172. }
  173. bool greenpak_is_ready()
  174. {
  175. return g_greenpak_is_ready;
  176. }
  177. #endif