greenpak.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. #include <gd32f4xx_gpio.h>
  30. #ifndef GREENPAK_I2C_PORT
  31. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length) { return false; }
  32. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length) { return false; }
  33. bool greenpak_load_firmware() { return false; }
  34. bool greenpak_is_ready() { return false; }
  35. #else
  36. bool g_greenpak_is_ready;
  37. // SCL is driven as push-pull, SDA is driven as IPU / OUT_OD
  38. #define I2C_SCL_HI() GPIO_BOP(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  39. #define I2C_SCL_LO() GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
  40. #define I2C_SDA_HI() gpio_mode_set(GREENPAK_I2C_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GREENPAK_I2C_SDA)
  41. #define I2C_SDA_LO() gpio_mode_set(GREENPAK_I2C_PORT, GPIO_MODE_OUTPUT, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SDA), gpio_output_options_set(GREENPAK_I2C_PORT,GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SDA), GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SDA
  42. #define I2C_SDA_READ() (GPIO_ISTAT(GREENPAK_I2C_PORT) & GREENPAK_I2C_SDA)
  43. #define I2C_DELAY() delay_ns(10000);
  44. static void greenpak_gpio_init()
  45. {
  46. gpio_bit_set(GREENPAK_I2C_PORT, GREENPAK_I2C_SCL | GREENPAK_I2C_SDA);
  47. gpio_mode_set(GREENPAK_I2C_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GREENPAK_I2C_SDA);
  48. gpio_mode_set(GREENPAK_I2C_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GREENPAK_I2C_SCL);
  49. gpio_output_options_set(GREENPAK_I2C_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SCL);
  50. // Data bits used for communication
  51. uint32_t greenpak_io = GREENPAK_PLD_IO1 | GREENPAK_PLD_IO2 | GREENPAK_PLD_IO3;
  52. gpio_bit_reset(SCSI_OUT_PORT, greenpak_io);
  53. gpio_mode_set(GREENPAK_PLD_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, greenpak_io);
  54. gpio_output_options_set(GREENPAK_PLD_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_200MHZ, greenpak_io);
  55. }
  56. static void i2c_writebit(bool bit)
  57. {
  58. if (bit)
  59. I2C_SDA_HI();
  60. else
  61. I2C_SDA_LO();
  62. I2C_DELAY();
  63. I2C_SCL_HI();
  64. I2C_DELAY();
  65. I2C_SCL_LO();
  66. }
  67. static bool i2c_readbit()
  68. {
  69. I2C_SDA_HI(); // Pull-up
  70. I2C_DELAY();
  71. I2C_SCL_HI();
  72. I2C_DELAY();
  73. bool result = I2C_SDA_READ();
  74. I2C_SCL_LO();
  75. return result;
  76. }
  77. // Write byte to I2C bus, return ACK bit status
  78. static bool i2c_writebyte(uint8_t byte)
  79. {
  80. for (int i = 0; i < 8; i++)
  81. {
  82. i2c_writebit(byte & (0x80 >> i));
  83. }
  84. return !i2c_readbit();
  85. }
  86. // Read byte from I2C bus
  87. static uint8_t i2c_readbyte(bool ack)
  88. {
  89. uint8_t result = 0;
  90. for (int i = 0; i < 8; i++)
  91. {
  92. result |= i2c_readbit() << (7 - i);
  93. }
  94. i2c_writebyte(!ack);
  95. return result;
  96. }
  97. static bool i2c_start(uint8_t device_addr)
  98. {
  99. // Initial signal state
  100. I2C_SCL_HI();
  101. I2C_SDA_HI();
  102. I2C_DELAY();
  103. // Start condition
  104. I2C_SDA_LO();
  105. I2C_DELAY();
  106. I2C_SCL_LO();
  107. I2C_DELAY();
  108. // Device address
  109. return i2c_writebyte(device_addr);
  110. }
  111. static void i2c_stop()
  112. {
  113. I2C_SDA_LO();
  114. I2C_DELAY();
  115. I2C_SCL_HI();
  116. I2C_DELAY();
  117. I2C_SDA_HI();
  118. I2C_DELAY();
  119. }
  120. bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length)
  121. {
  122. bool status = true;
  123. uint16_t blockaddr = regaddr >> 8;
  124. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  125. status &= i2c_writebyte(regaddr & 0xFF);
  126. for (int i = 0; i < length; i++)
  127. {
  128. status &= i2c_writebyte(data[i]);
  129. }
  130. i2c_stop();
  131. return status;
  132. }
  133. bool greenpak_read(uint16_t regaddr, uint8_t *data, int length)
  134. {
  135. bool status = true;
  136. uint16_t blockaddr = (regaddr >> 8) & 7;
  137. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
  138. status &= i2c_writebyte(regaddr & 0xFF);
  139. status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1) | 1);
  140. for (int i = 0; i < length; i++)
  141. {
  142. data[i] = i2c_readbyte(i < length - 1);
  143. }
  144. i2c_stop();
  145. return status;
  146. }
  147. bool greenpak_load_firmware()
  148. {
  149. uint8_t dummy;
  150. greenpak_gpio_init();
  151. if (!greenpak_read(0, &dummy, 1))
  152. {
  153. logmsg("Optional GreenPAK not detected");
  154. return false;
  155. }
  156. else
  157. {
  158. logmsg("Optional GreenPAK detected, loading firmware");
  159. }
  160. if (!greenpak_write(0, g_greenpak_fw, sizeof(g_greenpak_fw)))
  161. {
  162. logmsg("GreenPAK firmware loading failed");
  163. return false;
  164. }
  165. else
  166. {
  167. logmsg("GreenPAK firmware successfully loaded");
  168. LED_ON();
  169. delay(10);
  170. LED_OFF();
  171. delay(100);
  172. g_greenpak_is_ready = true;
  173. return true;
  174. }
  175. }
  176. bool greenpak_is_ready()
  177. {
  178. return g_greenpak_is_ready;
  179. }
  180. #endif