diff --git a/Production/Firmware/iidx_pico.uf2 b/Production/Firmware/iidx_pico.uf2 index 4367cad..f0d67bf 100644 Binary files a/Production/Firmware/iidx_pico.uf2 and b/Production/Firmware/iidx_pico.uf2 differ diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index 82b068c..bcd82f4 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -1,34 +1,34 @@ -set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack) -set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip) - -function(make_firmware board board_def) - pico_sdk_init() - add_executable(${board} - main.c cli.c commands.c buttons.c rgb.c save.c config.c setup.c - turntable.c tt_rainbow.c tt_blade.c - usb_descriptors.c) - target_compile_definitions(${board} PUBLIC ${board_def}) - pico_enable_stdio_usb(${board} 1) - pico_enable_stdio_uart(${board} 0) - - pico_generate_pio_header(${board} ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio) - - target_compile_options(${board} PRIVATE -Wfatal-errors -O3) - target_include_directories(${board} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) - target_include_directories(${board} PRIVATE - ${BTSTACK_ROOT}/src - ${LWIP_ROOT}/src/include) - - target_link_libraries(${board} PRIVATE - pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash - hardware_adc hardware_i2c hardware_watchdog - tinyusb_device tinyusb_board) - - pico_add_extra_outputs(${board}) - - add_custom_command(TARGET ${board} POST_BUILD - COMMAND cp ${board}.uf2 ${CMAKE_CURRENT_LIST_DIR}/..) -endfunction() - -make_firmware(iidx_pico BOARD_IIDX_PICO) - +set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack) +set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip) + +function(make_firmware board board_def) + pico_sdk_init() + add_executable(${board} + main.c cli.c commands.c buttons.c rgb.c save.c config.c setup.c + turntable.c as5600.c tmag5273.c tt_rainbow.c tt_blade.c + usb_descriptors.c) + target_compile_definitions(${board} PUBLIC ${board_def}) + pico_enable_stdio_usb(${board} 1) + pico_enable_stdio_uart(${board} 0) + + pico_generate_pio_header(${board} ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio) + + target_compile_options(${board} PRIVATE -Wfatal-errors -O3) + target_include_directories(${board} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + target_include_directories(${board} PRIVATE + ${BTSTACK_ROOT}/src + ${LWIP_ROOT}/src/include) + + target_link_libraries(${board} PRIVATE + pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash + hardware_adc hardware_i2c hardware_watchdog + tinyusb_device tinyusb_board) + + pico_add_extra_outputs(${board}) + + add_custom_command(TARGET ${board} POST_BUILD + COMMAND cp ${board}.uf2 ${CMAKE_CURRENT_LIST_DIR}/..) +endfunction() + +make_firmware(iidx_pico BOARD_IIDX_PICO) + diff --git a/firmware/src/as5600.c b/firmware/src/as5600.c new file mode 100644 index 0000000..d052901 --- /dev/null +++ b/firmware/src/as5600.c @@ -0,0 +1,59 @@ +/* + * AS5600 Angular Hall Sensor + * WHowe + * + */ + +#include "turntable.h" + +#include +#include +#include +#include + +#include "hardware/gpio.h" +#include "hardware/i2c.h" + +#include "board_defs.h" +#include "config.h" + +#define AS5600_ADDR 0x36 + +static i2c_inst_t *as5600_i2c = i2c0; +static uint16_t raw_angle = 0; + +void as5600_init(i2c_inst_t *i2c_port) +{ + as5600_i2c = i2c_port; +} + +bool as5600_init_sensor() +{ + return true; +} + +static bool as5600_is_present() +{ + uint8_t buf[1] = {0x0c}; + int ret = i2c_write_blocking_until(as5600_i2c, AS5600_ADDR, buf, 1, true, + make_timeout_time_ms(1)); + return ret == 1; +} + +int as5600_read_angle() +{ + uint8_t buf[2] = {0x0c, 0x00}; + int ret = i2c_write_blocking_until(as5600_i2c, AS5600_ADDR, buf, 1, true, + make_timeout_time_ms(1)); + if (ret != 1) { + return -1; + } + + ret = i2c_read_blocking_until(as5600_i2c, AS5600_ADDR, buf, 2, false, + make_timeout_time_ms(1)); + if (ret != 2) { + return -1; + } + + return (buf[0] & 0x0f) << 8 | buf[1]; +} diff --git a/firmware/src/as5600.h b/firmware/src/as5600.h new file mode 100644 index 0000000..e13d84d --- /dev/null +++ b/firmware/src/as5600.h @@ -0,0 +1,17 @@ +/* + * AS5600 Angular Hall Sensor + * WHowe + */ + +#ifndef AS5600_H +#define AS5600_H + +#include +#include + +void as5600_init(i2c_inst_t *i2c_port); +bool as5600_init_sensor(); +bool as5600_is_present(); +int as5600_read_angle(); + +#endif diff --git a/firmware/src/board_defs.h b/firmware/src/board_defs.h index 899dc34..8333d27 100644 --- a/firmware/src/board_defs.h +++ b/firmware/src/board_defs.h @@ -13,14 +13,12 @@ #define BUTTON_RGB_NUM 11 #define BUTTON_RGB_MAP { 6, 0, 5, 1, 4, 2, 3, 7, 8, 9, 10} - #define TT_RGB_PIN 28 #define TT_RGB_ORDER GRB // or RGB -#define TT_AS5600_ANALOG 26 -#define TT_AS5600_SCL 27 -#define TT_AS5600_SDA 26 -#define TT_AS5600_I2C i2c1 +#define TT_SENSOR_SCL 27 +#define TT_SENSOR_SDA 26 +#define TT_SENSOR_I2C i2c1 // Alternative I2C pins //#define TT_AS5600_SCL 21 diff --git a/firmware/src/tmag5273.c b/firmware/src/tmag5273.c new file mode 100644 index 0000000..629af9b --- /dev/null +++ b/firmware/src/tmag5273.c @@ -0,0 +1,120 @@ +/* + * TMAG5273 Angular Hall Sensor + * WHowe + * + */ + +#include +#include +#include + +#include "hardware/i2c.h" +#include "board_defs.h" + +#include "tmag5273.h" + +#define TMAG5273_DEF_ADDR 0x35 + +#define IO_TIMEOUT_US 1000 + +static struct { + i2c_inst_t *port; + uint8_t addr; + uint16_t cache; + bool present; +} instances[16] = { { i2c0, TMAG5273_DEF_ADDR } }; +#define INSTANCE_NUM count_of(instances) + +static int current_instance = 0; +#define INSTANCE instances[current_instance] + +#define I2C_PORT INSTANCE.port +#define I2C_ADDR INSTANCE.addr + +static void write_reg(uint8_t reg, uint8_t value) +{ + uint8_t data[2] = { reg, value }; + i2c_write_blocking_until(I2C_PORT, I2C_ADDR, data, 2, false, + time_us_64() + IO_TIMEOUT_US); +} + +static uint8_t read_reg(uint8_t reg) +{ + uint8_t value; + i2c_write_blocking_until(I2C_PORT, I2C_ADDR, ®, 1, true, + time_us_64() + IO_TIMEOUT_US); + i2c_read_blocking_until(I2C_PORT, I2C_ADDR, &value, 1, false, + time_us_64() + IO_TIMEOUT_US); + return value; +} + +static void read_many(uint8_t reg, uint8_t *dst, uint8_t len) +{ + i2c_write_blocking_until(I2C_PORT, I2C_ADDR, ®, 1, true, + time_us_64() + IO_TIMEOUT_US); + i2c_read_blocking_until(I2C_PORT, I2C_ADDR, dst, len, false, + time_us_64() + IO_TIMEOUT_US * len); +} + +void tmag5273_init(unsigned instance, i2c_inst_t *i2c_port) +{ + if (instance < INSTANCE_NUM) { + current_instance = instance; + INSTANCE.port = i2c_port; + INSTANCE.addr = TMAG5273_DEF_ADDR; + INSTANCE.present = tmag5273_change_addr(TMAG5273_DEF_ADDR + 1 + instance); + } +} + +void tmag5273_use(unsigned instance) +{ + if (instance < INSTANCE_NUM) { + current_instance = instance; + } +} + +bool tmag5273_is_present(unsigned instance) +{ + if (instance >= INSTANCE_NUM) { + return false; + } + return instances[instance].present; +} + +bool tmag5273_change_addr(uint8_t i2c_addr) +{ + tmag5273_write_reg(0x0c, (i2c_addr << 1) | 0x01); + INSTANCE.addr = i2c_addr; + tmag5273_read_reg(0x0c); // Dummy read + uint8_t new_addr = tmag5273_read_reg(0x0c) >> 1; + return new_addr == i2c_addr; +} + +bool tmag5273_init_sensor() +{ + tmag5273_write_reg(0x03, 0x01 << 2); // Enable angle calculation + tmag5273_write_reg(0x02, 0x03 << 4); // X-Y + tmag5273_write_reg(0x00, 0x03 << 2); // 8x average mode + tmag5273_write_reg(0x01, 0x02); // Continuous mode + return true; +} + +uint8_t tmag5273_read_reg(uint8_t addr) +{ + return read_reg(addr); +} + +void tmag5273_write_reg(uint8_t addr, uint8_t value) +{ + write_reg(addr, value); +} + +uint16_t tmag5273_read_angle() +{ + uint8_t buf[3] = { 0 }; + read_many(0x18, buf, sizeof(buf)); + if (buf[0] & 0x01) { + INSTANCE.cache = (buf[1] << 8 | buf[2]) & 0x1fff; + } + return INSTANCE.cache; +} diff --git a/firmware/src/tmag5273.h b/firmware/src/tmag5273.h new file mode 100644 index 0000000..297cd0c --- /dev/null +++ b/firmware/src/tmag5273.h @@ -0,0 +1,27 @@ +/* + * TMAG5273 Angular Hall Sensor + * WHowe + * + */ + +#ifndef TMAG5273_H +#define TMAG5273_H + +#include +#include + +#include "hardware/i2c.h" + +void tmag5273_init(unsigned instance, i2c_inst_t *i2c_port); +void tmag5273_use(unsigned instance); +bool tmag5273_is_present(unsigned instance); +bool tmag5273_change_addr(uint8_t i2c_addr); + +bool tmag5273_init_sensor(); + +uint8_t tmag5273_read_reg(uint8_t addr); +void tmag5273_write_reg(uint8_t addr, uint8_t value); + +uint16_t tmag5273_read_angle(); + +#endif \ No newline at end of file diff --git a/firmware/src/turntable.c b/firmware/src/turntable.c index 3d87d1e..8f6b056 100644 --- a/firmware/src/turntable.c +++ b/firmware/src/turntable.c @@ -15,45 +15,47 @@ #include "hardware/adc.h" #include "hardware/i2c.h" +#include "as5600.h" +#include "tmag5273.h" + #include "board_defs.h" #include "config.h" -static uint16_t angle = 0; - -static void init_i2c() -{ - i2c_init(TT_AS5600_I2C, 400 * 1000); - gpio_set_function(TT_AS5600_SCL, GPIO_FUNC_I2C); - gpio_set_function(TT_AS5600_SDA, GPIO_FUNC_I2C); - gpio_set_drive_strength(TT_AS5600_SCL, GPIO_DRIVE_STRENGTH_8MA); - gpio_set_drive_strength(TT_AS5600_SDA, GPIO_DRIVE_STRENGTH_8MA); - gpio_pull_up(TT_AS5600_SCL); - gpio_pull_up(TT_AS5600_SDA); -} +static uint16_t raw_angle = 0; +static bool use_as5600 = true; void turntable_init() { - init_i2c(); + i2c_init(TT_SENSOR_I2C, 400 * 1000); + gpio_init(TT_SENSOR_SCL); + gpio_init(TT_SENSOR_SDA); + gpio_set_function(TT_SENSOR_SCL, GPIO_FUNC_I2C); + gpio_set_function(TT_SENSOR_SDA, GPIO_FUNC_I2C); + gpio_pull_up(TT_SENSOR_SCL); + gpio_pull_up(TT_SENSOR_SDA); + + tmag5273_init(0, TT_SENSOR_I2C); + if (tmag5273_is_present(0)) { + tmag5273_use(0); + tmag5273_init_sensor(); + use_as5600 = false; + return; + } + + as5600_init(TT_SENSOR_I2C); + as5600_init_sensor(); + use_as5600 = true; } static int read_angle() { - const uint8_t as5600_addr = 0x36; - uint8_t buf[2] = {0x0c, 0x00}; - int ret = i2c_write_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 1, true, - make_timeout_time_ms(1)); - if (ret != 1) { - return -1; + if (use_as5600) { + return as5600_read_angle(); } - ret = i2c_read_blocking_until(TT_AS5600_I2C, as5600_addr, buf, 2, false, - make_timeout_time_ms(1)); - if (ret != 2) { - return -1; - } - - return (buf[0] & 0x0f) << 8 | buf[1]; + return tmag5273_read_angle() * 0x1000 / 360 / 16; } + void turntable_update() { int candidate = read_angle(); @@ -75,12 +77,12 @@ void turntable_update() } } - angle = candidate; + raw_angle = candidate; } uint16_t turntable_raw() { - return iidx_cfg->tt_sensor.reversed ? 4095 - angle : angle; // 12bit + return iidx_cfg->tt_sensor.reversed ? 4095 - raw_angle : raw_angle; // 12bit } uint8_t turntable_read() @@ -96,10 +98,10 @@ uint8_t turntable_read() } else if (iidx_cfg->tt_sensor.ppr == 3) { step = 4096 / 64; } else { - return angle >> 4; + return raw_angle >> 4; } - int16_t delta = angle - old_angle; + int16_t delta = raw_angle - old_angle; if (delta == 0) { return counter; } else if (delta > 2048) { diff --git a/firmware/src/turntable.h b/firmware/src/turntable.h index 33adfca..5337c21 100644 --- a/firmware/src/turntable.h +++ b/firmware/src/turntable.h @@ -1,17 +1,17 @@ -/* - * IIDX Controller Turntable - * WHowe - */ - -#ifndef TURNTABLE_H -#define TURNTABLE_H - -#include -#include - -void turntable_init(); -uint8_t turntable_read(); -uint16_t turntable_raw(); -void turntable_update(); - -#endif +/* + * IIDX Controller Turntable + * WHowe + */ + +#ifndef TURNTABLE_H +#define TURNTABLE_H + +#include +#include + +void turntable_init(); +uint8_t turntable_read(); +uint16_t turntable_raw(); +void turntable_update(); + +#endif