diff --git a/components/bm1397/CMakeLists.txt b/components/asic/CMakeLists.txt similarity index 97% rename from components/bm1397/CMakeLists.txt rename to components/asic/CMakeLists.txt index 77065556..25bd0560 100644 --- a/components/bm1397/CMakeLists.txt +++ b/components/asic/CMakeLists.txt @@ -1,5 +1,6 @@ idf_component_register( SRCS + "bm1370.c" "bm1368.c" "bm1366.c" "bm1397.c" diff --git a/components/bm1397/bm1366.c b/components/asic/bm1366.c similarity index 100% rename from components/bm1397/bm1366.c rename to components/asic/bm1366.c diff --git a/components/bm1397/bm1368.c b/components/asic/bm1368.c similarity index 100% rename from components/bm1397/bm1368.c rename to components/asic/bm1368.c diff --git a/components/asic/bm1370.c b/components/asic/bm1370.c new file mode 100644 index 00000000..b38a4857 --- /dev/null +++ b/components/asic/bm1370.c @@ -0,0 +1,504 @@ +#include "bm1370.h" + +#include "crc.h" +#include "global_state.h" +#include "serial.h" +#include "utils.h" + +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include +#include +#include +#include + +#define BM1370_RST_PIN GPIO_NUM_1 + +#define TYPE_JOB 0x20 +#define TYPE_CMD 0x40 + +#define GROUP_SINGLE 0x00 +#define GROUP_ALL 0x10 + +#define CMD_JOB 0x01 + +#define CMD_SETADDRESS 0x00 +#define CMD_WRITE 0x01 +#define CMD_READ 0x02 +#define CMD_INACTIVE 0x03 + +#define RESPONSE_CMD 0x00 +#define RESPONSE_JOB 0x80 + +#define SLEEP_TIME 20 +#define FREQ_MULT 25.0 + +#define CLOCK_ORDER_CONTROL_0 0x80 +#define CLOCK_ORDER_CONTROL_1 0x84 +#define ORDERED_CLOCK_ENABLE 0x20 +#define CORE_REGISTER_CONTROL 0x3C +#define PLL3_PARAMETER 0x68 +#define FAST_UART_CONFIGURATION 0x28 +#define TICKET_MASK 0x14 +#define MISC_CONTROL 0x18 + +typedef struct __attribute__((__packed__)) +{ + uint8_t preamble[2]; + uint32_t nonce; + uint8_t midstate_num; + uint8_t job_id; + uint16_t version; + uint8_t crc; +} asic_result; + +static const char * TAG = "bm1370Module"; + +static uint8_t asic_response_buffer[SERIAL_BUF_SIZE]; +static task_result result; + +/// @brief +/// @param ftdi +/// @param header +/// @param data +/// @param len +static void _send_BM1370(uint8_t header, uint8_t * data, uint8_t data_len, bool debug) +{ + packet_type_t packet_type = (header & TYPE_JOB) ? JOB_PACKET : CMD_PACKET; + uint8_t total_length = (packet_type == JOB_PACKET) ? (data_len + 6) : (data_len + 5); + + // allocate memory for buffer + unsigned char * buf = malloc(total_length); + + // add the preamble + buf[0] = 0x55; + buf[1] = 0xAA; + + // add the header field + buf[2] = header; + + // add the length field + buf[3] = (packet_type == JOB_PACKET) ? (data_len + 4) : (data_len + 3); + + // add the data + memcpy(buf + 4, data, data_len); + + // add the correct crc type + if (packet_type == JOB_PACKET) { + uint16_t crc16_total = crc16_false(buf + 2, data_len + 2); + buf[4 + data_len] = (crc16_total >> 8) & 0xFF; + buf[5 + data_len] = crc16_total & 0xFF; + } else { + buf[4 + data_len] = crc5(buf + 2, data_len + 2); + } + + // send serial data + SERIAL_send(buf, total_length, packet_type == CMD_PACKET ? BM1370_SERIALTX_DEBUG : false); + + free(buf); +} + +static void _send_simple(uint8_t * data, uint8_t total_length) +{ + unsigned char * buf = malloc(total_length); + memcpy(buf, data, total_length); + SERIAL_send(buf, total_length, false); + + free(buf); +} + +static void _send_chain_inactive(void) +{ + + unsigned char read_address[2] = {0x00, 0x00}; + // send serial data + _send_BM1370((TYPE_CMD | GROUP_ALL | CMD_INACTIVE), read_address, 2, false); +} + +static void _set_chip_address(uint8_t chipAddr) +{ + + unsigned char read_address[2] = {chipAddr, 0x00}; + // send serial data + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_SETADDRESS), read_address, 2, false); +} + +void BM1370_send_hash_frequency(int id, float target_freq, float max_diff) { + uint8_t freqbuf[6] = {0x00, 0x08, 0x40, 0xA0, 0x02, 0x41}; + uint8_t postdiv_min = 255; + uint8_t postdiv2_min = 255; + float best_freq = 0; + uint8_t best_refdiv = 0, best_fbdiv = 0, best_postdiv1 = 0, best_postdiv2 = 0; + + for (uint8_t refdiv = 2; refdiv > 0; refdiv--) { + for (uint8_t postdiv1 = 7; postdiv1 > 0; postdiv1--) { + for (uint8_t postdiv2 = 7; postdiv2 > 0; postdiv2--) { + uint16_t fb_divider = round(target_freq / 25.0 * (refdiv * postdiv2 * postdiv1)); + float newf = 25.0 * fb_divider / (refdiv * postdiv2 * postdiv1); + + if (fb_divider >= 0xa0 && fb_divider <= 0xef && + fabs(target_freq - newf) < max_diff && + postdiv1 >= postdiv2 && + postdiv1 * postdiv2 < postdiv_min && + postdiv2 <= postdiv2_min) { + + postdiv2_min = postdiv2; + postdiv_min = postdiv1 * postdiv2; + best_freq = newf; + best_refdiv = refdiv; + best_fbdiv = fb_divider; + best_postdiv1 = postdiv1; + best_postdiv2 = postdiv2; + } + } + } + } + + if (best_fbdiv == 0) { + ESP_LOGE(TAG, "Failed to find PLL settings for target frequency %.2f", target_freq); + return; + } + + freqbuf[2] = (best_fbdiv * 25 / best_refdiv >= 2400) ? 0x50 : 0x40; + freqbuf[3] = best_fbdiv; + freqbuf[4] = best_refdiv; + freqbuf[5] = (((best_postdiv1 - 1) & 0xf) << 4) | ((best_postdiv2 - 1) & 0xf); + + if (id != -1) { + freqbuf[0] = id * 2; + _send_BM1370(TYPE_CMD | GROUP_SINGLE | CMD_WRITE, freqbuf, 6, BM1370_SERIALTX_DEBUG); + } else { + _send_BM1370(TYPE_CMD | GROUP_ALL | CMD_WRITE, freqbuf, 6, BM1370_SERIALTX_DEBUG); + } + + //ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", target_freq, best_freq); +} + +static void do_frequency_ramp_up(float target_frequency) { + float current = 56.25; + float step = 6.25; + + ESP_LOGI(TAG, "Ramping up frequency from %.2f MHz to %.2f MHz with step %.2f MHz", current, target_frequency, step); + + BM1370_send_hash_frequency(-1, current, 0.001); + + while (current < target_frequency) { + float next_step = fminf(step, target_frequency - current); + current += next_step; + BM1370_send_hash_frequency(-1, current, 0.001); + vTaskDelay(pdMS_TO_TICKS(100)); + } +} + +static uint8_t _send_init(uint64_t frequency, uint16_t asic_count) +{ + + //enable and set version rolling mask to 0xFFFF + unsigned char init0[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C}; + _send_simple(init0, 11); + + //enable and set version rolling mask to 0xFFFF (again) + unsigned char init1[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C}; + _send_simple(init1, 11); + + //enable and set version rolling mask to 0xFFFF (again) + unsigned char init2[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C}; + _send_simple(init2, 11); + + //read register 00 on all chips (should respond AA 55 13 68 00 00 00 00 00 00 0F) + unsigned char init3[7] = {0x55, 0xAA, 0x52, 0x05, 0x00, 0x00, 0x0A}; + _send_simple(init3, 7); + + int chip_counter = 0; + while (true) { + if (SERIAL_rx(asic_response_buffer, 11, 1000) > 0) { + chip_counter++; + } else { + break; + } + } + ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count); + + //enable and set version rolling mask to 0xFFFF (again) + unsigned char init4[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C}; + _send_simple(init4, 11); + + //Reg_A8 + unsigned char init5[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA8, 0x00, 0x07, 0x00, 0x00, 0x03}; + _send_simple(init5, 11); + + //Misc Control + //**TX: 55 AA 51 09 00 18 F0 00 C1 00 04 //command all chips, write chip address 00, register 18, data F0 00 C1 00 - Misc Control + //unsigned char init6[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x18, 0xF0, 0x00, 0xC1, 0x00, 0x04}; //from S21Pro dump + unsigned char init6[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x18, 0xFF, 0x0F, 0xC1, 0x00, 0x00}; + _send_simple(init6, 11); + + //chain inactive + _send_chain_inactive(); + // unsigned char init7[7] = {0x55, 0xAA, 0x53, 0x05, 0x00, 0x00, 0x03}; + // _send_simple(init7, 7); + + // split the chip address space evenly + uint8_t address_interval = (uint8_t) (256 / chip_counter); + for (uint8_t i = 0; i < chip_counter; i++) { + _set_chip_address(i * address_interval); + // unsigned char init8[7] = {0x55, 0xAA, 0x40, 0x05, 0x00, 0x00, 0x1C}; + // _send_simple(init8, 7); + } + + //Core Register Control + unsigned char init9[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x8B, 0x00, 0x12}; + _send_simple(init9, 11); + + //Core Register Control + //**TX: 55 AA 51 09 00 3C 80 00 80 0C 11 //command all chips, write chip address 00, register 3C, data 80 00 80 0C - Core Register Control + //unsigned char init10[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x80, 0x0C, 0x11}; //from S21Pro dump + unsigned char init10[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x80, 0x18, 0x1F}; + _send_simple(init10, 11); + + //set ticket mask + // unsigned char init11[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x14, 0x00, 0x00, 0x00, 0xFF, 0x08}; + // _send_simple(init11, 11); + BM1370_set_job_difficulty_mask(BM1370_INITIAL_DIFFICULTY); + + //Analog Mux Control + unsigned char init12[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x54, 0x00, 0x00, 0x00, 0x03, 0x1D}; + _send_simple(init12, 11); + + //Set the IO Driver Strength on chip 00 + //**TX: 55 AA 51 09 00 58 00 01 11 11 0D //command all chips, write chip address 00, register 58, data 01 11 11 11 - Set the IO Driver Strength on chip 00 + //unsigned char init13[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x58, 0x00, 0x01, 0x11, 0x11, 0x0D}; //from S21Pro dump + unsigned char init13[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x58, 0x02, 0x11, 0x11, 0x11, 0x06}; + _send_simple(init13, 11); + + for (uint8_t i = 0; i < chip_counter; i++) { + //Reg_A8 + unsigned char set_a8_register[6] = {i * address_interval, 0xA8, 0x00, 0x07, 0x01, 0xF0}; + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_WRITE), set_a8_register, 6, false); + //Misc Control + unsigned char set_18_register[6] = {i * address_interval, 0x18, 0xF0, 0x00, 0xC1, 0x00}; + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_WRITE), set_18_register, 6, false); + //Core Register Control + unsigned char set_3c_register_first[6] = {i * address_interval, 0x3C, 0x80, 0x00, 0x8B, 0x00}; + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_WRITE), set_3c_register_first, 6, false); + //Core Register Control + //unsigned char set_3c_register_second[6] = {i * address_interval, 0x3C, 0x80, 0x00, 0x80, 0x0C}; //from S21Pro dump + unsigned char set_3c_register_second[6] = {i * address_interval, 0x3C, 0x80, 0x00, 0x80, 0x18}; + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_WRITE), set_3c_register_second, 6, false); + //Core Register Control + unsigned char set_3c_register_third[6] = {i * address_interval, 0x3C, 0x80, 0x00, 0x82, 0xAA}; + _send_BM1370((TYPE_CMD | GROUP_SINGLE | CMD_WRITE), set_3c_register_third, 6, false); + } + + do_frequency_ramp_up(frequency); + + //BM1370_send_hash_frequency(frequency); + + //register 10 is still a bit of a mystery. discussion: https://github.com/skot/ESP-Miner/pull/167 + + // unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x11, 0x5A}; //S19k Pro Default + // unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x14, 0x46}; //S19XP-Luxos Default + // unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x15, 0x1C}; //S19XP-Stock Default + //unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x15, 0xA4}; //S21-Stock Default + unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x1E, 0xB5}; //S21 Pro-Stock Default + // unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x0F, 0x00, 0x00}; //supposedly the "full" 32bit nonce range + _send_BM1370((TYPE_CMD | GROUP_ALL | CMD_WRITE), set_10_hash_counting, 6, false); + + return chip_counter; +} + +// reset the BM1370 via the RTS line +static void _reset(void) +{ + gpio_set_level(BM1370_RST_PIN, 0); + + // delay for 100ms + vTaskDelay(100 / portTICK_PERIOD_MS); + + // set the gpio pin high + gpio_set_level(BM1370_RST_PIN, 1); + + // delay for 100ms + vTaskDelay(100 / portTICK_PERIOD_MS); +} + +static void _send_read_address(void) +{ + + unsigned char read_address[2] = {0x00, 0x00}; + // send serial data + _send_BM1370((TYPE_CMD | GROUP_ALL | CMD_READ), read_address, 2, false); +} + +uint8_t BM1370_init(uint64_t frequency, uint16_t asic_count) +{ + ESP_LOGI(TAG, "Initializing BM1370"); + + memset(asic_response_buffer, 0, SERIAL_BUF_SIZE); + + esp_rom_gpio_pad_select_gpio(BM1370_RST_PIN); + gpio_set_direction(BM1370_RST_PIN, GPIO_MODE_OUTPUT); + + // reset the bm1370 + _reset(); + + return _send_init(frequency, asic_count); +} + +// Baud formula = 25M/((denominator+1)*8) +// The denominator is 5 bits found in the misc_control (bits 9-13) +int BM1370_set_default_baud(void) +{ + // default divider of 26 (11010) for 115,749 + unsigned char baudrate[9] = {0x00, MISC_CONTROL, 0x00, 0x00, 0b01111010, 0b00110001}; // baudrate - misc_control + _send_BM1370((TYPE_CMD | GROUP_ALL | CMD_WRITE), baudrate, 6, false); + return 115749; +} + +int BM1370_set_max_baud(void) +{ + // divider of 0 for 3,125,000 + ESP_LOGI(TAG, "Setting max baud of 1000000 "); + + unsigned char init8[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0x28, 0x11, 0x30, 0x02, 0x00, 0x03}; + _send_simple(init8, 11); + return 1000000; +} + + +void BM1370_set_job_difficulty_mask(int difficulty) +{ + // Default mask of 256 diff + unsigned char job_difficulty_mask[9] = {0x00, TICKET_MASK, 0b00000000, 0b00000000, 0b00000000, 0b11111111}; + + // The mask must be a power of 2 so there are no holes + // Correct: {0b00000000, 0b00000000, 0b11111111, 0b11111111} + // Incorrect: {0b00000000, 0b00000000, 0b11100111, 0b11111111} + // (difficulty - 1) if it is a pow 2 then step down to second largest for more hashrate sampling + difficulty = _largest_power_of_two(difficulty) - 1; + + // convert difficulty into char array + // Ex: 256 = {0b00000000, 0b00000000, 0b00000000, 0b11111111}, {0x00, 0x00, 0x00, 0xff} + // Ex: 512 = {0b00000000, 0b00000000, 0b00000001, 0b11111111}, {0x00, 0x00, 0x01, 0xff} + for (int i = 0; i < 4; i++) { + char value = (difficulty >> (8 * i)) & 0xFF; + // The char is read in backwards to the register so we need to reverse them + // So a mask of 512 looks like 0b00000000 00000000 00000001 1111111 + // and not 0b00000000 00000000 10000000 1111111 + + job_difficulty_mask[5 - i] = _reverse_bits(value); + } + + ESP_LOGI(TAG, "Setting ASIC difficulty mask to %d", difficulty); + + _send_BM1370((TYPE_CMD | GROUP_ALL | CMD_WRITE), job_difficulty_mask, 6, false); +} + +static uint8_t id = 0; + +void BM1370_send_work(void * pvParameters, bm_job * next_bm_job) +{ + + GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; + + BM1370_job job; + id = (id + 24) % 128; + job.job_id = id; + job.num_midstates = 0x01; + memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4); + memcpy(&job.nbits, &next_bm_job->target, 4); + memcpy(&job.ntime, &next_bm_job->ntime, 4); + memcpy(job.merkle_root, next_bm_job->merkle_root_be, 32); + memcpy(job.prev_block_hash, next_bm_job->prev_block_hash_be, 32); + memcpy(&job.version, &next_bm_job->version, 4); + + if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) { + free_bm_job(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id]); + } + + GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] = next_bm_job; + + pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock); + GLOBAL_STATE->valid_jobs[job.job_id] = 1; + //ESP_LOGI(TAG, "Send Job: %02X", job.job_id); + pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock); + + _send_BM1370((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), &job, sizeof(BM1370_job), false); +} + +asic_result * BM1370_receive_work(void) +{ + // wait for a response, wait time is pretty arbitrary + int received = SERIAL_rx(asic_response_buffer, 11, 60000); + + if (received < 0) { + ESP_LOGI(TAG, "Error in serial RX"); + return NULL; + } else if (received == 0) { + // Didn't find a solution, restart and try again + return NULL; + } + + if (received != 11 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55) { + ESP_LOGI(TAG, "Serial RX invalid %i", received); + ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received); + SERIAL_clear_buffer(); + return NULL; + } + + return (asic_result *) asic_response_buffer; +} + +static uint16_t reverse_uint16(uint16_t num) +{ + return (num >> 8) | (num << 8); +} + +static uint32_t reverse_uint32(uint32_t val) +{ + return ((val >> 24) & 0xff) | // Move byte 3 to byte 0 + ((val << 8) & 0xff0000) | // Move byte 1 to byte 2 + ((val >> 8) & 0xff00) | // Move byte 2 to byte 1 + ((val << 24) & 0xff000000); // Move byte 0 to byte 3 +} + +task_result * BM1370_proccess_work(void * pvParameters) +{ + + asic_result * asic_result = BM1370_receive_work(); + + if (asic_result == NULL) { + return NULL; + } + + // uint8_t job_id = asic_result->job_id; + // uint8_t rx_job_id = ((int8_t)job_id & 0xf0) >> 1; + // ESP_LOGI(TAG, "Job ID: %02X, RX: %02X", job_id, rx_job_id); + + // uint8_t job_id = asic_result->job_id & 0xf8; + // ESP_LOGI(TAG, "Job ID: %02X, Core: %01X", job_id, asic_result->job_id & 0x07); + + uint8_t job_id = (asic_result->job_id & 0xf0) >> 1; + uint8_t core_id = (uint8_t)((reverse_uint32(asic_result->nonce) >> 25) & 0x7f); // BM1370 has 80 cores, so it should be coded on 7 bits + uint8_t small_core_id = asic_result->job_id & 0x0f; // BM1370 has 16 small cores, so it should be coded on 4 bits + uint32_t version_bits = (reverse_uint16(asic_result->version) << 13); // shift the 16 bit value left 13 + ESP_LOGI(TAG, "Job ID: %02X, Core: %d/%d, Ver: %08" PRIX32, job_id, core_id, small_core_id, version_bits); + + GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; + + if (GLOBAL_STATE->valid_jobs[job_id] == 0) { + ESP_LOGE(TAG, "Invalid job nonce found, 0x%02X", job_id); + return NULL; + } + + uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits; + + result.job_id = job_id; + result.nonce = asic_result->nonce; + result.rolled_version = rolled_version; + + return &result; +} diff --git a/components/bm1397/bm1397.c b/components/asic/bm1397.c similarity index 100% rename from components/bm1397/bm1397.c rename to components/asic/bm1397.c diff --git a/components/bm1397/crc.c b/components/asic/crc.c similarity index 100% rename from components/bm1397/crc.c rename to components/asic/crc.c diff --git a/components/bm1397/include/bm1366.h b/components/asic/include/bm1366.h similarity index 100% rename from components/bm1397/include/bm1366.h rename to components/asic/include/bm1366.h diff --git a/components/bm1397/include/bm1368.h b/components/asic/include/bm1368.h similarity index 100% rename from components/bm1397/include/bm1368.h rename to components/asic/include/bm1368.h diff --git a/components/asic/include/bm1370.h b/components/asic/include/bm1370.h new file mode 100644 index 00000000..ddec5c07 --- /dev/null +++ b/components/asic/include/bm1370.h @@ -0,0 +1,46 @@ +#ifndef BM1370_H_ +#define BM1370_H_ + +#include "common.h" +#include "driver/gpio.h" +#include "mining.h" + +#define CRC5_MASK 0x1F + +#define BM1370_INITIAL_DIFFICULTY 256 + +#define BM1370_SERIALTX_DEBUG true +#define BM1370_SERIALRX_DEBUG false +#define BM1370_DEBUG_WORK false //causes insane amount of debug output + +static const uint64_t BM1370_CORE_COUNT = 128; +static const uint64_t BM1370_SMALL_CORE_COUNT = 2040; + +typedef struct +{ + float frequency; +} bm1370Module; + +typedef struct __attribute__((__packed__)) +{ + uint8_t job_id; + uint8_t num_midstates; + uint8_t starting_nonce[4]; + uint8_t nbits[4]; + uint8_t ntime[4]; + uint8_t merkle_root[32]; + uint8_t prev_block_hash[32]; + uint8_t version[4]; +} BM1370_job; + +uint8_t BM1370_init(uint64_t frequency, uint16_t asic_count); + +uint8_t BM1370_send_init(void); +void BM1370_send_work(void * GLOBAL_STATE, bm_job * next_bm_job); +void BM1370_set_job_difficulty_mask(int); +int BM1370_set_max_baud(void); +int BM1370_set_default_baud(void); +void BM1370_send_hash_frequency(int, float, float); +task_result * BM1370_proccess_work(void * GLOBAL_STATE); + +#endif /* BM1370_H_ */ diff --git a/components/bm1397/include/bm1397.h b/components/asic/include/bm1397.h similarity index 100% rename from components/bm1397/include/bm1397.h rename to components/asic/include/bm1397.h diff --git a/components/bm1397/include/common.h b/components/asic/include/common.h similarity index 100% rename from components/bm1397/include/common.h rename to components/asic/include/common.h diff --git a/components/bm1397/include/crc.h b/components/asic/include/crc.h similarity index 100% rename from components/bm1397/include/crc.h rename to components/asic/include/crc.h diff --git a/components/bm1397/include/serial.h b/components/asic/include/serial.h similarity index 100% rename from components/bm1397/include/serial.h rename to components/asic/include/serial.h diff --git a/components/bm1397/serial.c b/components/asic/serial.c similarity index 100% rename from components/bm1397/serial.c rename to components/asic/serial.c diff --git a/components/bm1397/test/CMakeLists.txt b/components/asic/test/CMakeLists.txt similarity index 100% rename from components/bm1397/test/CMakeLists.txt rename to components/asic/test/CMakeLists.txt diff --git a/components/bm1397/test/test_job_command.c b/components/asic/test/test_job_command.c similarity index 100% rename from components/bm1397/test/test_job_command.c rename to components/asic/test/test_job_command.c diff --git a/config-600.cvs b/config-600.cvs new file mode 100644 index 00000000..fb961a27 --- /dev/null +++ b/config-600.cvs @@ -0,0 +1,19 @@ +key,type,encoding,value +main,namespace,, +hostname,data,string,bitaxe +wifissid,data,string,myssid +wifipass,data,string,mypass +stratumurl,data,string,public-pool.io +stratumport,data,u16,21496 +stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe +stratumpass,data,string,x +asicfrequency,data,u16,490 +asicvoltage,data,u16,1100 +asicmodel,data,string,BM1370 +devicemodel,data,string,gamma +boardversion,data,string,600 +flipscreen,data,u16,1 +invertfanpol,data,u16,1 +autofanspeed,data,u16,0 +fanspeed,data,u16,100 +selftest,data,u16,0 \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index dcf0026e..ad639a59 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -28,7 +28,7 @@ INCLUDE_DIRS "." "tasks" "http_server" - "../components/bm1397/include" + "../components/asic/include" "../components/connect/include" "../components/dns_server/include" "../components/stratum/include" diff --git a/main/EMC2101.c b/main/EMC2101.c index 65a31804..82860b7f 100644 --- a/main/EMC2101.c +++ b/main/EMC2101.c @@ -62,10 +62,10 @@ float EMC2101_get_external_temp(void) reading >>= 5; if (reading == EMC2101_TEMP_FAULT_OPEN_CIRCUIT) { - ESP_LOGE(TAG, "EMC2101 TEMP_FAULT_OPEN_CIRCUIT"); + ESP_LOGE(TAG, "EMC2101 TEMP_FAULT_OPEN_CIRCUIT: %04X", reading); } if (reading == EMC2101_TEMP_FAULT_SHORT) { - ESP_LOGE(TAG, "EMC2101 TEMP_FAULT_SHORT"); + ESP_LOGE(TAG, "EMC2101 TEMP_FAULT_SHORT: %04X", reading); } float result = (float) reading / 8.0; diff --git a/main/global_state.h b/main/global_state.h index 47945537..280e665b 100644 --- a/main/global_state.h +++ b/main/global_state.h @@ -4,6 +4,7 @@ #include #include #include "asic_task.h" +#include "bm1370.h" #include "bm1368.h" #include "bm1366.h" #include "bm1397.h" @@ -24,6 +25,7 @@ typedef enum DEVICE_MAX, DEVICE_ULTRA, DEVICE_SUPRA, + DEVICE_GAMMA, } DeviceModel; typedef enum @@ -32,6 +34,7 @@ typedef enum ASIC_BM1397, ASIC_BM1366, ASIC_BM1368, + ASIC_BM1370, } AsicModel; typedef struct diff --git a/main/http_server/axe-os/src/app/components/edit/edit.component.html b/main/http_server/axe-os/src/app/components/edit/edit.component.html index 8dc1e00c..f1d2ac97 100644 --- a/main/http_server/axe-os/src/app/components/edit/edit.component.html +++ b/main/http_server/axe-os/src/app/components/edit/edit.component.html @@ -71,6 +71,38 @@ + + +
+ +
+ +
+
+ +
+ + +
+
+ + +
+ +
+ +
+
+ +
+ + +
+
@@ -146,7 +178,7 @@
- +
oled_buf, 0, 20); snprintf(module->oled_buf, 20, msg); @@ -38,6 +39,7 @@ static bool fan_sense_pass(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: fan_speed = EMC2101_get_fan_speed(); break; default: @@ -88,6 +90,7 @@ void self_test(void * pvParameters) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: // turn ASIC on gpio_set_direction(GPIO_NUM_10, GPIO_MODE_OUTPUT); gpio_set_level(GPIO_NUM_10, 0); @@ -106,6 +109,7 @@ void self_test(void * pvParameters) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1)); EMC2101_set_fan_speed(1); break; @@ -117,6 +121,7 @@ void self_test(void * pvParameters) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (!OLED_init()) { ESP_LOGE(TAG, "OLED init failed!"); } else { @@ -141,6 +146,8 @@ void self_test(void * pvParameters) } } break; + case DEVICE_GAMMA: + break; default: } diff --git a/main/system.c b/main/system.c index d46a54a5..a05f5447 100644 --- a/main/system.c +++ b/main/system.c @@ -111,6 +111,7 @@ static void _init_system(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1)); break; default: @@ -128,6 +129,7 @@ static void _init_system(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: // oled if (!OLED_init()) { ESP_LOGI(TAG, "OLED init failed!"); @@ -160,6 +162,7 @@ static void _show_overheat_screen(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { OLED_clearLine(0); OLED_clearLine(1); @@ -188,6 +191,7 @@ static void _update_hashrate(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: float efficiency = GLOBAL_STATE->POWER_MANAGEMENT_MODULE.power / (module->current_hashrate / 1000.0); OLED_clearLine(0); memset(module->oled_buf, 0, 20); @@ -210,6 +214,7 @@ static void _update_shares(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: OLED_clearLine(1); memset(module->oled_buf, 0, 20); snprintf(module->oled_buf, 20, "A/R: %llu/%llu", module->shares_accepted, module->shares_rejected); @@ -231,6 +236,7 @@ static void _update_best_diff(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: OLED_clearLine(3); memset(module->oled_buf, 0, 20); snprintf(module->oled_buf, 20, module->FOUND_BLOCK ? "!!! BLOCK FOUND !!!" : "BD: %s", module->best_diff_string); @@ -246,6 +252,7 @@ static void _clear_display(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: OLED_clearLine(0); OLED_clearLine(1); OLED_clearLine(2); @@ -264,6 +271,7 @@ static void _update_system_info(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { memset(module->oled_buf, 0, 20); @@ -298,6 +306,7 @@ static void _update_esp32_info(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { memset(module->oled_buf, 0, 20); @@ -331,6 +340,7 @@ static void _init_connection(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { memset(module->oled_buf, 0, 20); snprintf(module->oled_buf, 20, "Connecting to SSID:"); @@ -349,6 +359,7 @@ static void _update_connection(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { OLED_clearLine(2); strncpy(module->oled_buf, module->ssid, sizeof(module->oled_buf)); @@ -385,6 +396,7 @@ static void _update_system_performance(GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { _update_hashrate(GLOBAL_STATE); @@ -406,6 +418,7 @@ static void show_ap_information(const char * error, GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: if (OLED_status()) { _clear_display(GLOBAL_STATE); if (error != NULL) { diff --git a/main/tasks/power_management_task.c b/main/tasks/power_management_task.c index 03968db4..6657fa33 100644 --- a/main/tasks/power_management_task.c +++ b/main/tasks/power_management_task.c @@ -26,6 +26,9 @@ #define TPS546_THROTTLE_TEMP 105.0 #define TPS546_MAX_TEMP 145.0 +#define SUPRA_POWER_OFFSET 5 +#define GAMMA_POWER_OFFSET 5 + static const char * TAG = "power_management"; static float _fbound(float value, float lower_bound, float upper_bound) @@ -60,6 +63,7 @@ static double automatic_fan_speed(float chip_temp, GlobalState * GLOBAL_STATE) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: float perc = (float) result / 100; GLOBAL_STATE->POWER_MANAGEMENT_MODULE.fan_perc = perc; EMC2101_set_fan_speed( perc ); @@ -109,10 +113,12 @@ void POWER_MANAGEMENT_task(void * pvParameters) } } break; + case DEVICE_GAMMA: + break; default: } - vTaskDelay(3000 / portTICK_PERIOD_MS); + vTaskDelay(4000 / portTICK_PERIOD_MS); while (1) { @@ -125,88 +131,115 @@ void POWER_MANAGEMENT_task(void * pvParameters) power_management->current = TPS546_get_iout() * 1000; // calculate regulator power (in milliwatts) power_management->power = (TPS546_get_vout() * power_management->current) / 1000; + // The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for. + power_management->power += SUPRA_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better. } else if (INA260_installed() == true) { power_management->voltage = INA260_read_voltage(); power_management->current = INA260_read_current(); power_management->power = INA260_read_power() / 1000; } - power_management->fan_rpm = EMC2101_get_fan_speed(); - + break; + case DEVICE_GAMMA: + power_management->voltage = TPS546_get_vin() * 1000; + power_management->current = TPS546_get_iout() * 1000; + // calculate regulator power (in milliwatts) + power_management->power = (TPS546_get_vout() * power_management->current) / 1000; + // The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for. + power_management->power += GAMMA_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better. break; default: } - if (GLOBAL_STATE->asic_model == ASIC_BM1397) { + power_management->fan_rpm = EMC2101_get_fan_speed(); - switch (GLOBAL_STATE->device_model) { - case DEVICE_MAX: - case DEVICE_ULTRA: - case DEVICE_SUPRA: - power_management->chip_temp_avg = EMC2101_get_external_temp(); + switch (GLOBAL_STATE->device_model) { + case DEVICE_MAX: + power_management->chip_temp_avg = EMC2101_get_external_temp(); - if ((power_management->chip_temp_avg > THROTTLE_TEMP) && - (power_management->frequency_value > 50 || power_management->voltage > 1000)) { - ESP_LOGE(TAG, "OVERHEAT ASIC %fC", power_management->chip_temp_avg ); + if ((power_management->chip_temp_avg > THROTTLE_TEMP) && + (power_management->frequency_value > 50 || power_management->voltage > 1000)) { + ESP_LOGE(TAG, "OVERHEAT ASIC %fC", power_management->chip_temp_avg ); - EMC2101_set_fan_speed(1); - if (power_management->HAS_POWER_EN) { - gpio_set_level(GPIO_NUM_10, 1); - } - nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000); - nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50); - nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100); - nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0); - exit(EXIT_FAILURE); - } - break; - - default: - } - } else if (GLOBAL_STATE->asic_model == ASIC_BM1366 || GLOBAL_STATE->asic_model == ASIC_BM1368) { - switch (GLOBAL_STATE->device_model) { - case DEVICE_MAX: - case DEVICE_ULTRA: - case DEVICE_SUPRA: - - if (GLOBAL_STATE->board_version == 402) { - power_management->chip_temp_avg = EMC2101_get_external_temp(); - power_management->vr_temp = (float)TPS546_get_temperature(); - } else { - power_management->chip_temp_avg = EMC2101_get_internal_temp() + 5; - power_management->vr_temp = 0.0; - } - - // EMC2101 will give bad readings if the ASIC is turned off - if(power_management->voltage < TPS546_INIT_VOUT_MIN){ - break; + EMC2101_set_fan_speed(1); + if (power_management->HAS_POWER_EN) { + gpio_set_level(GPIO_NUM_10, 1); } + nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000); + nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50); + nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100); + nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0); + exit(EXIT_FAILURE); + } + break; + case DEVICE_ULTRA: + case DEVICE_SUPRA: + + if (GLOBAL_STATE->board_version == 402) { + power_management->chip_temp_avg = EMC2101_get_external_temp(); + power_management->vr_temp = (float)TPS546_get_temperature(); + } else { + power_management->chip_temp_avg = EMC2101_get_internal_temp() + 5; + power_management->vr_temp = 0.0; + } - if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) && - (power_management->frequency_value > 50 || power_management->voltage > 1000)) { - ESP_LOGE(TAG, "OVERHEAT VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg ); - - EMC2101_set_fan_speed(1); - if (GLOBAL_STATE->board_version == 402) { - // Turn off core voltage - VCORE_set_voltage(0.0, GLOBAL_STATE); - } else if (power_management->HAS_POWER_EN) { - gpio_set_level(GPIO_NUM_10, 1); - } - nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000); - nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50); - nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100); - nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0); - nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1); - exit(EXIT_FAILURE); - } - + // EMC2101 will give bad readings if the ASIC is turned off + if(power_management->voltage < TPS546_INIT_VOUT_MIN){ break; + } - default: - } + //overheat mode if the voltage regulator or ASIC is too hot + if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) && + (power_management->frequency_value > 50 || power_management->voltage > 1000)) { + ESP_LOGE(TAG, "OVERHEAT! VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg ); + + EMC2101_set_fan_speed(1); + if (GLOBAL_STATE->board_version == 402) { + // Turn off core voltage + VCORE_set_voltage(0.0, GLOBAL_STATE); + } else if (power_management->HAS_POWER_EN) { + gpio_set_level(GPIO_NUM_10, 1); + } + nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000); + nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50); + nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100); + nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0); + nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1); + exit(EXIT_FAILURE); + } + + break; + case DEVICE_GAMMA: + power_management->chip_temp_avg = EMC2101_get_external_temp(); + power_management->vr_temp = (float)TPS546_get_temperature(); + + // EMC2101 will give bad readings if the ASIC is turned off + if(power_management->voltage < TPS546_INIT_VOUT_MIN){ + break; + } + + //overheat mode if the voltage regulator or ASIC is too hot + if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) && + (power_management->frequency_value > 50 || power_management->voltage > 1000)) { + ESP_LOGE(TAG, "OVERHEAT! VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg ); + + EMC2101_set_fan_speed(1); + + // Turn off core voltage + VCORE_set_voltage(0.0, GLOBAL_STATE); + + nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000); + nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50); + nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100); + nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0); + nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1); + exit(EXIT_FAILURE); + } + break; + default: } + if (auto_fan_speed == 1) { power_management->fan_perc = (float)automatic_fan_speed(power_management->chip_temp_avg, GLOBAL_STATE); @@ -216,6 +249,7 @@ void POWER_MANAGEMENT_task(void * pvParameters) case DEVICE_MAX: case DEVICE_ULTRA: case DEVICE_SUPRA: + case DEVICE_GAMMA: float fs = (float) nvs_config_get_u16(NVS_CONFIG_FAN_SPEED, 100); power_management->fan_perc = fs; @@ -238,4 +272,3 @@ void POWER_MANAGEMENT_task(void * pvParameters) vTaskDelay(POLL_RATE / portTICK_PERIOD_MS); } } - diff --git a/main/vcore.c b/main/vcore.c index 7c48354c..738b3a7c 100644 --- a/main/vcore.c +++ b/main/vcore.c @@ -22,8 +22,19 @@ static const char *TAG = "vcore.c"; void VCORE_init(GlobalState * global_state) { - if (global_state->board_version == 402) { - TPS546_init(); + switch (global_state->device_model) { + case DEVICE_MAX: + case DEVICE_ULTRA: + case DEVICE_SUPRA: + if (global_state->board_version == 402) { + TPS546_init(); + } + break; + case DEVICE_GAMMA: + TPS546_init(); + break; + // case DEVICE_HEX: + default: } ADC_init(); } @@ -71,6 +82,10 @@ bool VCORE_set_voltage(float core_voltage, GlobalState * global_state) DS4432U_set_current_code(0, reg_setting); /// eek! } break; + case DEVICE_GAMMA: + ESP_LOGI(TAG, "Set ASIC voltage = %.3fV", core_voltage); + TPS546_set_vout(core_voltage * (float)global_state->voltage_domain); + break; // case DEVICE_HEX: default: }