#include "bus.h" #include "esp/gpio.h" #include #include #include "log.h" uint32_t spi_transfer_32_duplex(uint8_t bus, uint32_t val) { uint32_t out = val; uint32_t in; spi_transfer(bus, &out, &in, 1, SPI_32BIT); return in; } uint16_t spi_transfer_16_duplex(uint8_t bus, uint32_t val) { uint16_t out = val; uint16_t in; spi_transfer(bus, &out, &in, 1, SPI_16BIT); return in; } typedef enum { CMD_NONE = 0, CMD_READ = 1, CMD_WRITE = 2, CMD_INIT = 3, CMD_RESET = 4, CMD_VERSION = 5, CMD_CONFIG = 6, CMD_PING = 7 } bus_cmd; typedef union { struct { unsigned dat: 16; unsigned addr: 8; unsigned cmd: 8; } __attribute__((packed)); uint32_t _; } request_frame; typedef union { struct { unsigned dat: 16; unsigned addr: 8; unsigned flags: 7; unsigned: 1; } __attribute__((packed)); uint32_t _; } reply_frame; uint8_t flags = 0; reply_frame bus_transfer_msg(bus_cmd cmd, uint8_t addr, uint16_t dat) { request_frame frame_out = {._=0}; reply_frame frame_in = {._=0}; frame_out.cmd = cmd; frame_out.addr = addr; frame_out.dat = dat; spi_transfer_32_duplex(1, frame_out._); for (volatile int k = 0; k < 512 * 2; ++k); frame_in._ = spi_transfer_32_duplex(1, 0x0000); for (volatile int k = 0; k < 512 * 2; ++k); flags |= frame_in.flags; return frame_in; } uint32_t bus_transfer_msg(uint8_t addr, uint16_t dat) { return bus_transfer_msg(CMD_WRITE, addr, dat)._; } bool bus_transfer_msg_arr(uint8_t addr, uint16_t *dat, uint8_t len) { request_frame frame_out = {._=0}; reply_frame frame_in = {._=0}; request_frame last_frame = {._=0}; uint8_t error_count = 0; for (int i = 0; i < len; ++i) { frame_out.cmd = CMD_WRITE; frame_out.addr = addr; frame_out.dat = dat[i]; frame_in._ = spi_transfer_32_duplex(1, frame_out._); if(frame_in.dat != last_frame.dat && i != 0) { error_count++; if(0) { syslog(" > "); syslog_i32(frame_out._); syslog(" < "); syslog_i32(frame_in._); syslog(" =? "); syslog_i32(last_frame._); syslog("\n"); } printf(" > %08x < %08x =? %08x\n", frame_out._, frame_in._, last_frame._); } last_frame._ = frame_out._; for (volatile int k = 0; k < 512 * 2; ++k); } frame_in._ = spi_transfer_32_duplex(1, 0x0000); if(frame_in.dat != last_frame.dat) { error_count++; if(0) { syslog(" > "); syslog_i32(frame_out._); syslog(" < "); syslog_i32(frame_in._); syslog(" =? "); syslog_i32(last_frame._); syslog("\n"); } printf(" > %08x < %08x =? %08x\n", 0, frame_in._, last_frame._); } return error_count == 0; } uint16_t bus_get_version() { return bus_transfer_msg(15, 0) >> 16; } void reset_bus() { gpio_write(4, false); for (volatile int k = 0; k < 128; ++k); gpio_write(4, true); } bool bus_init() { gpio_enable(12, GPIO_INPUT); gpio_set_pullup(12, true, true); gpio_write(4, false); for (volatile int k = 0; k < 512 * 2; ++k); gpio_write(4, true); gpio_enable(4, GPIO_OUT_OPEN_DRAIN); gpio_write(4, true); for (volatile int k = 0; k < 512 * 4; ++k); bool miso_state = gpio_read(12); if(miso_state) { printf("MISO is high, bus is not reset\n"); return false; } spi_init(1, SPI_MODE0, SPI_FREQ_DIV_8M, true, SPI_BIG_ENDIAN, false); return true; } bool bus_init_next() { flags &= ~0x04; auto reply = bus_transfer_msg(CMD_INIT, 1, 0); //printf(" init: %08x \n", reply.flags); printf(" init: %02x %02x %04x %08x \n", reply.flags, reply.addr, reply.dat, reply._); return reply.flags & 0x04; } uint16_t ping_count = 0; bool bus_ping() { auto reply = bus_transfer_msg(CMD_PING, 1, ++ping_count); if(reply.dat == ping_count) return true; printf("ping %02x %04x =? %08x\n", 1, ping_count, reply._); return false; }