| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- // I2C communication with GreenPAK.
- // This uses bitbanging for I2C so that internal GPIO pull-up can be used
- // and to avoid the bugs that are present in STM32F2 I2C peripheral,
- // it is uncertain if the same bugs apply to GD32F2.
- #include "AzulSCSI_platform.h"
- #include "AzulSCSI_log.h"
- #include "greenpak.h"
- #include "greenpak_fw.h"
- #ifndef GREENPAK_I2C_PORT
- bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length) { return false; }
- bool greenpak_read(uint16_t regaddr, uint8_t *data, int length) { return false; }
- bool greenpak_load_firmware() { return false; }
- bool greenpak_is_ready() { return false; }
- #else
- bool g_greenpak_is_ready;
- // SCL is driven as push-pull, SDA is driven as IPU / OUT_OD
- #define I2C_SCL_HI() GPIO_BOP(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
- #define I2C_SCL_LO() GPIO_BC(GREENPAK_I2C_PORT) = GREENPAK_I2C_SCL
- #define I2C_SDA_HI() gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA)
- #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
- #define I2C_SDA_READ() (GPIO_ISTAT(GREENPAK_I2C_PORT) & GREENPAK_I2C_SDA)
- #define I2C_DELAY() delay_ns(10000);
- static void greenpak_gpio_init()
- {
- gpio_bit_set(GREENPAK_I2C_PORT, GREENPAK_I2C_SCL | GREENPAK_I2C_SDA);
- gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_IPU, 0, GREENPAK_I2C_SDA);
- gpio_init(GREENPAK_I2C_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GREENPAK_I2C_SCL);
- // Data bits used for communication
- uint32_t greenpak_io = GREENPAK_PLD_IO1 | GREENPAK_PLD_IO2 | GREENPAK_PLD_IO3;
- gpio_bit_reset(SCSI_OUT_PORT, greenpak_io);
- gpio_init(SCSI_OUT_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, greenpak_io);
- }
- static void i2c_writebit(bool bit)
- {
- if (bit)
- I2C_SDA_HI();
- else
- I2C_SDA_LO();
- I2C_DELAY();
- I2C_SCL_HI();
- I2C_DELAY();
- I2C_SCL_LO();
- }
- static bool i2c_readbit()
- {
- I2C_SDA_HI(); // Pull-up
- I2C_DELAY();
- I2C_SCL_HI();
- I2C_DELAY();
- bool result = I2C_SDA_READ();
- I2C_SCL_LO();
- return result;
- }
- // Write byte to I2C bus, return ACK bit status
- static bool i2c_writebyte(uint8_t byte)
- {
- for (int i = 0; i < 8; i++)
- {
- i2c_writebit(byte & (0x80 >> i));
- }
- return !i2c_readbit();
- }
- // Read byte from I2C bus
- static uint8_t i2c_readbyte(bool ack)
- {
- uint8_t result = 0;
- for (int i = 0; i < 8; i++)
- {
- result |= i2c_readbit() << (7 - i);
- }
- i2c_writebyte(!ack);
- return result;
- }
- static bool i2c_start(uint8_t device_addr)
- {
- // Initial signal state
- I2C_SCL_HI();
- I2C_SDA_HI();
- I2C_DELAY();
- // Start condition
- I2C_SDA_LO();
- I2C_DELAY();
-
- I2C_SCL_LO();
- I2C_DELAY();
- // Device address
- return i2c_writebyte(device_addr);
- }
- static void i2c_stop()
- {
- I2C_SDA_LO();
- I2C_DELAY();
- I2C_SCL_HI();
- I2C_DELAY();
- I2C_SDA_HI();
- I2C_DELAY();
- }
- bool greenpak_write(uint16_t regaddr, const uint8_t *data, int length)
- {
- bool status = true;
- uint16_t blockaddr = regaddr >> 8;
- status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
- status &= i2c_writebyte(regaddr & 0xFF);
-
- for (int i = 0; i < length; i++)
- {
- status &= i2c_writebyte(data[i]);
- }
- i2c_stop();
- return status;
- }
- bool greenpak_read(uint16_t regaddr, uint8_t *data, int length)
- {
- bool status = true;
- uint16_t blockaddr = (regaddr >> 8) & 7;
- status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1));
- status &= i2c_writebyte(regaddr & 0xFF);
- status &= i2c_start(GREENPAK_I2C_ADDR | (blockaddr << 1) | 1);
-
- for (int i = 0; i < length; i++)
- {
- data[i] = i2c_readbyte(i < length - 1);
- }
- i2c_stop();
- return status;
- }
- bool greenpak_load_firmware()
- {
- uint8_t dummy;
- greenpak_gpio_init();
- if (!greenpak_read(0, &dummy, 1))
- {
- azlog("Optional GreenPAK not detected");
- return false;
- }
- else
- {
- azlog("Optional GreenPAK detected, loading firmware");
- }
- if (!greenpak_write(0, g_greenpak_fw, sizeof(g_greenpak_fw)))
- {
- azlog("GreenPAK firmware loading failed");
- return false;
- }
- else
- {
- azlog("GreenPAK firmware successfully loaded");
- LED_ON();
- delay(10);
- LED_OFF();
- delay(100);
- g_greenpak_is_ready = true;
- return true;
- }
- }
- bool greenpak_is_ready()
- {
- return g_greenpak_is_ready;
- }
- #endif
|