Add RP2040 bootloader related stuff

This commit is contained in:
Renze Nicolai 2022-04-29 05:24:17 +02:00
parent f6c5666f20
commit bba2bbfad4
4 changed files with 108 additions and 22 deletions

View file

@ -118,21 +118,29 @@ esp_err_t board_init(bool* aLcdReady) {
return res; return res;
} }
// FPGA uint8_t rp2040_fw_version;
dev_ice40.spi_bus = SPI_BUS; if (rp2040_get_firmware_version(&dev_rp2040, &rp2040_fw_version) != ESP_OK) {
dev_ice40.pin_cs = GPIO_SPI_CS_FPGA; ESP_LOGE(TAG, "Initializing RP2040 failed to read firmware version");
dev_ice40.pin_done = -1; return ESP_FAIL;
dev_ice40.pin_reset = -1; }
dev_ice40.pin_int = GPIO_INT_FPGA;
dev_ice40.spi_speed = 10000000; // 10 MHz //23000000; // 23MHz
dev_ice40.spi_max_transfer_size = SPI_MAX_TRANSFER_SIZE;
dev_ice40.get_done = ice40_get_done_wrapper;
dev_ice40.set_reset = ice40_set_reset_wrapper;
res = ice40_init(&dev_ice40); if (rp2040_fw_version != 0xFF) { // Only init FPGA when RP2040 is not in bootloader mode
if (res != ESP_OK) { // FPGA
ESP_LOGE(TAG, "Initializing FPGA failed"); dev_ice40.spi_bus = SPI_BUS;
return res; dev_ice40.pin_cs = GPIO_SPI_CS_FPGA;
dev_ice40.pin_done = -1;
dev_ice40.pin_reset = -1;
dev_ice40.pin_int = GPIO_INT_FPGA;
dev_ice40.spi_speed = 23000000; // 23MHz
dev_ice40.spi_max_transfer_size = SPI_MAX_TRANSFER_SIZE;
dev_ice40.get_done = ice40_get_done_wrapper;
dev_ice40.set_reset = ice40_set_reset_wrapper;
res = ice40_init(&dev_ice40);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Initializing FPGA failed");
return res;
}
} }
// BNO055 sensor on system I2C bus // BNO055 sensor on system I2C bus

View file

@ -51,15 +51,14 @@ void rp2040_intr_handler(void *arg) {
esp_err_t rp2040_init(RP2040* device) { esp_err_t rp2040_init(RP2040* device) {
esp_err_t res; esp_err_t res;
uint8_t firmware_version; res = rp2040_get_firmware_version(device, &device->_fw_version);
res = rp2040_get_firmware_version(device, &firmware_version);
if (res != ESP_OK) { if (res != ESP_OK) {
ESP_LOGE(TAG, "Failed to read firmware version"); ESP_LOGE(TAG, "Failed to read firmware version");
return res; return res;
} }
if (firmware_version != 1) { if (device->_fw_version < 1) {
ESP_LOGE(TAG, "Unsupported RP2040 firmware version (%u) found", firmware_version); ESP_LOGE(TAG, "Unsupported RP2040 firmware version (%u) found", device->_fw_version);
return ESP_ERR_INVALID_VERSION; return ESP_ERR_INVALID_VERSION;
} }
@ -106,13 +105,36 @@ esp_err_t rp2040_get_firmware_version(RP2040* device, uint8_t* version) {
return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_FW_VER, version, 1); return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_FW_VER, version, 1);
} }
esp_err_t rp2040_get_bootloader_version(RP2040* device, uint8_t* version) {
if (device->_fw_version != 0xFF) return ESP_FAIL;
return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_BL_REG_BL_VER, version, 1);
}
esp_err_t rp2040_get_bootloader_state(RP2040* device, uint8_t* state) {
if (device->_fw_version != 0xFF) return ESP_FAIL;
return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_BL_REG_BL_STATE, state, 1);
}
esp_err_t rp2040_set_bootloader_ctrl(RP2040* device, uint8_t action) {
if (device->_fw_version != 0xFF) return ESP_FAIL;
return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_BL_REG_BL_CTRL, &action, 1);
}
esp_err_t rp2040_reboot_to_bootloader(RP2040* device) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
uint8_t value = 0xBE;
return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_REG_BL_TRIGGER, &value, 1);
}
esp_err_t rp2040_get_gpio_dir(RP2040* device, uint8_t gpio, bool* direction) { esp_err_t rp2040_get_gpio_dir(RP2040* device, uint8_t gpio, bool* direction) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
esp_err_t res = i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_GPIO_DIR, &device->_gpio_direction, 1); esp_err_t res = i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_GPIO_DIR, &device->_gpio_direction, 1);
if (res != ESP_OK) return res; if (res != ESP_OK) return res;
*direction = (device->_gpio_direction >> gpio) & 0x01; *direction = (device->_gpio_direction >> gpio) & 0x01;
return ESP_OK; return ESP_OK;
} }
esp_err_t rp2040_set_gpio_dir(RP2040* device, uint8_t gpio, bool direction) { esp_err_t rp2040_set_gpio_dir(RP2040* device, uint8_t gpio, bool direction) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
if (direction) { if (direction) {
device->_gpio_direction |= 1UL << gpio; device->_gpio_direction |= 1UL << gpio;
} else { } else {
@ -122,6 +144,7 @@ esp_err_t rp2040_set_gpio_dir(RP2040* device, uint8_t gpio, bool direction) {
} }
esp_err_t rp2040_get_gpio_value(RP2040* device, uint8_t gpio, bool* value) { esp_err_t rp2040_get_gpio_value(RP2040* device, uint8_t gpio, bool* value) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
uint8_t reg_value; uint8_t reg_value;
esp_err_t res = i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_GPIO_IN, &reg_value, 1); esp_err_t res = i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_GPIO_IN, &reg_value, 1);
if (res != ESP_OK) return res; if (res != ESP_OK) return res;
@ -130,6 +153,7 @@ esp_err_t rp2040_get_gpio_value(RP2040* device, uint8_t gpio, bool* value) {
} }
esp_err_t rp2040_set_gpio_value(RP2040* device, uint8_t gpio, bool value) { esp_err_t rp2040_set_gpio_value(RP2040* device, uint8_t gpio, bool value) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
if (value) { if (value) {
device->_gpio_value |= 1UL << gpio; device->_gpio_value |= 1UL << gpio;
} else { } else {
@ -139,18 +163,22 @@ esp_err_t rp2040_set_gpio_value(RP2040* device, uint8_t gpio, bool value) {
} }
esp_err_t rp2040_get_lcd_backlight(RP2040* device, uint8_t* brightness) { esp_err_t rp2040_get_lcd_backlight(RP2040* device, uint8_t* brightness) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_LCD_BACKLIGHT, brightness, 1); return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_LCD_BACKLIGHT, brightness, 1);
} }
esp_err_t rp2040_set_lcd_backlight(RP2040* device, uint8_t brightness) { esp_err_t rp2040_set_lcd_backlight(RP2040* device, uint8_t brightness) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_OK; // Ignore if unsupported
return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_REG_LCD_BACKLIGHT, &brightness, 1); return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_REG_LCD_BACKLIGHT, &brightness, 1);
} }
esp_err_t rp2040_set_fpga(RP2040* device, bool enabled) { esp_err_t rp2040_set_fpga(RP2040* device, bool enabled) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
uint8_t value = enabled ? 0x01 : 0x00; uint8_t value = enabled ? 0x01 : 0x00;
return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_REG_FPGA, &value, 1); return i2c_write_reg_n(device->i2c_bus, device->i2c_address, RP2040_REG_FPGA, &value, 1);
} }
esp_err_t rp2040_read_buttons(RP2040* device, uint16_t* value) { esp_err_t rp2040_read_buttons(RP2040* device, uint16_t* value) {
if ((device->_fw_version < 0x01) && (device->_fw_version >= 0xFF)) return ESP_FAIL;
return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_INPUT1, (uint8_t*) value, 2); return i2c_read_reg(device->i2c_bus, device->i2c_address, RP2040_REG_INPUT1, (uint8_t*) value, 2);
} }

View file

@ -25,6 +25,7 @@ enum {
RP2040_REG_ADC_VALUE_VBAT1, RP2040_REG_ADC_VALUE_VBAT1,
RP2040_REG_ADC_VALUE_VBAT2, RP2040_REG_ADC_VALUE_VBAT2,
RP2040_REG_USB, RP2040_REG_USB,
RP2040_REG_BL_TRIGGER,
RP2040_REG_SCRATCH0, // Used by the ESP32 to store boot parameters, can also be read and written to from WebUSB RP2040_REG_SCRATCH0, // Used by the ESP32 to store boot parameters, can also be read and written to from WebUSB
RP2040_REG_SCRATCH1, RP2040_REG_SCRATCH1,
RP2040_REG_SCRATCH2, RP2040_REG_SCRATCH2,
@ -91,6 +92,13 @@ enum {
RP2040_REG_SCRATCH63 RP2040_REG_SCRATCH63
}; };
enum {
RP2040_BL_REG_FW_VER,
RP2040_BL_REG_BL_VER,
RP2040_BL_REG_BL_STATE,
RP2040_BL_REG_BL_CTRL
};
enum { enum {
RP2040_INPUT_BUTTON_HOME = 0, RP2040_INPUT_BUTTON_HOME = 0,
RP2040_INPUT_BUTTON_MENU, RP2040_INPUT_BUTTON_MENU,
@ -119,6 +127,7 @@ typedef struct {
xSemaphoreHandle _intr_trigger; xSemaphoreHandle _intr_trigger;
uint8_t _gpio_direction; uint8_t _gpio_direction;
uint8_t _gpio_value; uint8_t _gpio_value;
uint8_t _fw_version;
} RP2040; } RP2040;
typedef struct _rp2040_input_message { typedef struct _rp2040_input_message {
@ -130,6 +139,11 @@ esp_err_t rp2040_init(RP2040* device);
esp_err_t rp2040_get_firmware_version(RP2040* device, uint8_t* version); esp_err_t rp2040_get_firmware_version(RP2040* device, uint8_t* version);
esp_err_t rp2040_get_bootloader_version(RP2040* device, uint8_t* version);
esp_err_t rp2040_get_bootloader_state(RP2040* device, uint8_t* state);
esp_err_t rp2040_set_bootloader_ctrl(RP2040* device, uint8_t action);
esp_err_t rp2040_reboot_to_bootloader(RP2040* device);
esp_err_t rp2040_get_gpio_dir(RP2040* device, uint8_t gpio, bool* direction); esp_err_t rp2040_get_gpio_dir(RP2040* device, uint8_t gpio, bool* direction);
esp_err_t rp2040_set_gpio_dir(RP2040* device, uint8_t gpio, bool direction); esp_err_t rp2040_set_gpio_dir(RP2040* device, uint8_t gpio, bool direction);

View file

@ -268,10 +268,44 @@ void app_main(void) {
} }
ws2812_init(GPIO_LED_DATA); ws2812_init(GPIO_LED_DATA);
uint8_t ledBuffer[15] = {50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t ledBuffer[15] = {50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0};
ws2812_send_data(ledBuffer, sizeof(ledBuffer)); ws2812_send_data(ledBuffer, sizeof(ledBuffer));
//fpga_test(ili9341, ice40, rp2040->queue); uint8_t fw_version;
if (rp2040_get_firmware_version(rp2040, &fw_version) != ESP_OK) {
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "RP2040 FW VERSION READ FAILED");
restart();
}
if (fw_version == 0xFF) {
// RP2040 is in bootloader mode
char buffer[255] = {0};
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "RP2040 BL");
uint8_t bl_version;
if (rp2040_get_bootloader_version(rp2040, &bl_version) != ESP_OK) {
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "RP2040 BL VERSION READ FAILED");
restart();
}
while (true) {
uint8_t bl_state;
if (rp2040_get_bootloader_state(rp2040, &bl_state) != ESP_OK) {
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "RP2040 BL STATE READ FAILED");
restart();
}
snprintf(buffer, sizeof(buffer), "RP2040 BL (%02X): %02X", bl_version, bl_state);
graphics_task(pax_buffer, ili9341, framebuffer, NULL, buffer);
vTaskDelay(200 / portTICK_PERIOD_MS);
if (bl_state == 0xB0) {
printf("SYNC");
}
}
return;
}
/*while (true) {
fpga_test(ili9341, ice40, rp2040->queue);
vTaskDelay(200 / portTICK_PERIOD_MS);
}*/
/*while (true) { /*while (true) {
uint16_t state; uint16_t state;
@ -297,7 +331,9 @@ void app_main(void) {
appfs_boot_app(appfs_fd); appfs_boot_app(appfs_fd);
} else if (menu_action == ACTION_FPGA) { } else if (menu_action == ACTION_FPGA) {
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "FPGA TEST"); graphics_task(pax_buffer, ili9341, framebuffer, NULL, "FPGA TEST");
fpga_test(ili9341, ice40, rp2040->queue); //fpga_test(ili9341, ice40, rp2040->queue);
rp2040_reboot_to_bootloader(rp2040);
restart();
} else if (menu_action == ACTION_INSTALLER) { } else if (menu_action == ACTION_INSTALLER) {
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "INSTALLER"); graphics_task(pax_buffer, ili9341, framebuffer, NULL, "INSTALLER");
//appfs_store_app(); //appfs_store_app();