mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-07-27 08:46:01 -04:00
Cpld autodetect & boot splash screen (#1888)
* added delayed error message when hackrf cpld initialization fails * refactoring * implemented portapack cpld autodetection * refactoring * fixed valid config range * added lcd fast setup * added boot splash screen * added one frame delay to remove flickering * fixed config persistence
This commit is contained in:
parent
8725b01995
commit
c3add0ce84
7 changed files with 357 additions and 137 deletions
|
@ -28,6 +28,7 @@
|
|||
#include "hackrf_hal.hpp"
|
||||
#include "hackrf_gpio.hpp"
|
||||
using namespace hackrf::one;
|
||||
#include "jtag_target_gpio.hpp"
|
||||
|
||||
#include "clock_manager.hpp"
|
||||
#include "event_m0.hpp"
|
||||
|
@ -50,6 +51,7 @@ using asahi_kasei::ak4951::AK4951;
|
|||
#include "file.hpp"
|
||||
#include "sd_card.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "bitmap.hpp"
|
||||
|
||||
namespace portapack {
|
||||
|
||||
|
@ -174,50 +176,21 @@ constexpr I2CConfig i2c_config_fast_clock{
|
|||
enum class PortaPackModel {
|
||||
R1_20150901,
|
||||
R2_20170522,
|
||||
AGM,
|
||||
AUTODETECT,
|
||||
};
|
||||
|
||||
static bool save_config(int8_t value) {
|
||||
persistent_memory::set_config_cpld(value);
|
||||
if (sd_card::status() == sd_card::Status::Mounted) {
|
||||
ensure_directory("/hardware");
|
||||
File file;
|
||||
auto sucess = file.create("/hardware/settings.txt");
|
||||
if (!sucess.is_valid()) {
|
||||
file.write_line(to_string_dec_uint(value));
|
||||
}
|
||||
}
|
||||
portapack::persistent_memory::cache::persist();
|
||||
return true;
|
||||
}
|
||||
|
||||
int read_file(std::string name) {
|
||||
std::string return_string = "";
|
||||
File file;
|
||||
auto success = file.open(name);
|
||||
|
||||
if (!success.is_valid()) {
|
||||
char one_char[1];
|
||||
for (size_t pointer = 0; pointer < file.size(); pointer++) {
|
||||
file.seek(pointer);
|
||||
file.read(one_char, 1);
|
||||
return_string += one_char[0];
|
||||
}
|
||||
return std::stoi(return_string);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_config() {
|
||||
static Optional<int> config_value;
|
||||
if (!config_value.is_valid()) {
|
||||
int8_t value = portapack::persistent_memory::config_cpld();
|
||||
if ((value <= 0 || value >= 5) && sd_card::status() == sd_card::Status::Mounted) {
|
||||
int data = read_file("/hardware/settings.txt");
|
||||
if (data != -1) {
|
||||
config_value = data;
|
||||
}
|
||||
} else {
|
||||
config_value = value;
|
||||
}
|
||||
config_value = value;
|
||||
}
|
||||
return config_value.value();
|
||||
}
|
||||
|
@ -226,39 +199,49 @@ static PortaPackModel portapack_model() {
|
|||
static Optional<PortaPackModel> model;
|
||||
|
||||
if (!model.is_valid()) {
|
||||
const auto switches_state = get_switches_state();
|
||||
// Only save config if no other multi key boot action is triggered (like pmem reset)
|
||||
if (switches_state.count() == 1) {
|
||||
if (switches_state[(size_t)ui::KeyEvent::Up]) {
|
||||
jtag::GPIOTarget target{
|
||||
portapack::gpio_cpld_tck,
|
||||
portapack::gpio_cpld_tms,
|
||||
portapack::gpio_cpld_tdi,
|
||||
portapack::gpio_cpld_tdo};
|
||||
jtag::JTAG jtag{target};
|
||||
portapack::cpld::CPLD cpld{jtag};
|
||||
|
||||
cpld.reset();
|
||||
cpld.run_test_idle();
|
||||
uint32_t idcode = cpld.get_idcode();
|
||||
if (idcode == 0x25610) {
|
||||
model = PortaPackModel::AGM;
|
||||
} else {
|
||||
const auto switches_state = swizzled_switches();
|
||||
// chDbgPanic(to_string_hex((uint32_t)switches_state.count(), 8).c_str());
|
||||
// Only save config if no other multi key boot action is triggered (like pmem reset)
|
||||
if (((switches_state >> (size_t)ui::KeyEvent::Up) & 1) == 1) {
|
||||
save_config(1);
|
||||
// model = PortaPackModel::R2_20170522; // Commented these out as they should be set down below anyway
|
||||
} else if (switches_state[(size_t)ui::KeyEvent::Down]) {
|
||||
} else if (((switches_state >> (size_t)ui::KeyEvent::Down) & 1) == 1) {
|
||||
save_config(2);
|
||||
// model = PortaPackModel::R1_20150901;
|
||||
} else if (switches_state[(size_t)ui::KeyEvent::Left]) {
|
||||
} else if (((switches_state >> (size_t)ui::KeyEvent::Left) & 1) == 1) {
|
||||
save_config(3);
|
||||
// model = PortaPackModel::R1_20150901;
|
||||
} else if (switches_state[(size_t)ui::KeyEvent::Right]) {
|
||||
} else if (((switches_state >> (size_t)ui::KeyEvent::Right) & 1) == 1) {
|
||||
save_config(4);
|
||||
// model = PortaPackModel::R2_20170522;
|
||||
} else if (switches_state[(size_t)ui::KeyEvent::Select]) {
|
||||
} else if (((switches_state >> (size_t)ui::KeyEvent::Select) & 1) == 1) {
|
||||
save_config(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (load_config() == 1) {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else if (load_config() == 2) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 3) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 4) {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else {
|
||||
if (audio_codec_wm8731.detected()) {
|
||||
model = PortaPackModel::R1_20150901; // H1R1
|
||||
if (load_config() == 1) {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else if (load_config() == 2) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 3) {
|
||||
model = PortaPackModel::R1_20150901;
|
||||
} else if (load_config() == 4) {
|
||||
model = PortaPackModel::R2_20170522;
|
||||
} else {
|
||||
model = PortaPackModel::R2_20170522; // H1R2, H2, H2+
|
||||
model = PortaPackModel::AUTODETECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,6 +328,129 @@ static void shutdown_base() {
|
|||
clock_manager.shutdown();
|
||||
}
|
||||
|
||||
static void set_cpu_clock_speed() {
|
||||
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
|
||||
* core clock speed to the 110 - 204MHz range.
|
||||
*/
|
||||
|
||||
/* Step into the 90-110MHz M4 clock range */
|
||||
/* OG:
|
||||
* Fclkin = 40M
|
||||
* /N=2 = 20M = PFDin
|
||||
* Fcco = PFDin * (M=10) = 200M
|
||||
* r9:
|
||||
* Fclkin = 10M
|
||||
* /N=1 = 10M = PFDin
|
||||
* Fcco = PFDin * (M=20) = 200M
|
||||
* Fclk = Fcco / (2*(P=1)) = 100M
|
||||
*/
|
||||
cgu::pll1::ctrl({
|
||||
.pd = 1,
|
||||
.bypass = 0,
|
||||
.fbsel = 0,
|
||||
.direct = 0,
|
||||
.psel = 0,
|
||||
.autoblock = 1,
|
||||
.nsel = hackrf_r9 ? 0UL : 1UL,
|
||||
.msel = hackrf_r9 ? 19UL : 9UL,
|
||||
.clk_sel = cgu::CLK_SEL::GP_CLKIN,
|
||||
});
|
||||
|
||||
cgu::pll1::enable();
|
||||
while (!cgu::pll1::is_locked())
|
||||
;
|
||||
|
||||
set_clock_config(clock_config_pll1_step);
|
||||
|
||||
/* Delay >50us at 90-110MHz clock speed */
|
||||
volatile uint32_t delay = 1400;
|
||||
while (delay--)
|
||||
;
|
||||
|
||||
set_clock_config(clock_config_pll1);
|
||||
|
||||
/* Remove /2P divider from PLL1 output to achieve full speed */
|
||||
cgu::pll1::direct();
|
||||
}
|
||||
|
||||
static void draw_splash_screen_icon(int16_t n, const ui::Bitmap& bitmap) {
|
||||
ui::Painter painter;
|
||||
|
||||
painter.draw_bitmap(
|
||||
{portapack::display.width() / 2 - 8 - 40 + (n * 20), portapack::display.height() / 2 - 8 + 40},
|
||||
bitmap,
|
||||
ui::Color::white(),
|
||||
ui::Color::black());
|
||||
}
|
||||
|
||||
static bool is_portapack_present() {
|
||||
systime_t timeout = 50;
|
||||
uint8_t wm8731_reset_command[] = {0x0f, 0x00};
|
||||
if (i2c0.transmit(0x1a /* wm8731 */, wm8731_reset_command, 2, timeout) == false) {
|
||||
audio_codec_ak4951.reset();
|
||||
uint8_t ak4951_init_command[] = {0x00, 0x00};
|
||||
i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout);
|
||||
chThdSleepMilliseconds(10);
|
||||
if (i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout) == false) {
|
||||
shutdown_base();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_portapack_cpld() {
|
||||
switch (portapack_model()) {
|
||||
case PortaPackModel::AUTODETECT: {
|
||||
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_autodetect(
|
||||
portapack::cpld::rev_20150901::config, portapack::cpld::rev_20170522::config);
|
||||
if (result != portapack::cpld::CpldUpdateStatus::Success) {
|
||||
shutdown_base();
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case PortaPackModel::R1_20150901:
|
||||
case PortaPackModel::R2_20170522: {
|
||||
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
|
||||
if (result == portapack::cpld::CpldUpdateStatus::Program_failed) {
|
||||
chThdSleepMilliseconds(10);
|
||||
// Mode left (R1) and right (R2,H2,H2+) bypass going into hackrf mode after failing CPLD update
|
||||
// Mode center (autodetect), up (R1) and down (R2,H2,H2+) will go into hackrf mode after failing CPLD update
|
||||
if (load_config() != 3 /* left */ && load_config() != 4 /* right */) {
|
||||
shutdown_base();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case PortaPackModel::AGM:
|
||||
// the AGM devices are always factory flashed. so do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void initialize_boot_splash_screen() {
|
||||
ui::Painter painter;
|
||||
portapack::display.init();
|
||||
|
||||
painter.fill_rectangle(
|
||||
{0, 0, portapack::display.width(), portapack::display.height()},
|
||||
ui::Color::black());
|
||||
|
||||
chThdSleepMilliseconds(17);
|
||||
portapack::backlight()->on();
|
||||
|
||||
painter.draw_bitmap(
|
||||
{portapack::display.width() / 2 - 40, portapack::display.height() / 2 - 8},
|
||||
ui::bitmap_titlebar_image,
|
||||
ui::Color::white(),
|
||||
ui::Color::black());
|
||||
}
|
||||
|
||||
/* Clock scheme after exiting bootloader in SPIFI mode:
|
||||
*
|
||||
* XTAL_OSC = powered down
|
||||
|
@ -396,23 +502,24 @@ init_status_t init() {
|
|||
|
||||
i2c0.start(i2c_config_boot_clock);
|
||||
|
||||
// Keeping this here for now incase we need to revert
|
||||
// if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
|
||||
// shutdown_base();
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if( !hackrf::cpld::load_sram() ) {
|
||||
// chSysHalt();
|
||||
// }
|
||||
chThdSleepMilliseconds(100);
|
||||
|
||||
configure_pins_portapack();
|
||||
|
||||
portapack::io.init();
|
||||
persistent_memory::cache::init();
|
||||
|
||||
const auto switches_state = swizzled_switches() & (~(0xC0 | 0x80));
|
||||
bool lcd_fast_setup = switches_state == 0 && portapack::display.read_display_status();
|
||||
|
||||
if (lcd_fast_setup) {
|
||||
initialize_boot_splash_screen();
|
||||
} else {
|
||||
if (check_portapack_cpld() == false)
|
||||
return init_status_t::INIT_PORTAPACK_CPLD_FAILED;
|
||||
}
|
||||
|
||||
/* Cache some configuration data from persistent memory. */
|
||||
persistent_memory::cache::init();
|
||||
rtc_time::dst_init();
|
||||
chThdSleepMilliseconds(10);
|
||||
|
||||
|
@ -425,48 +532,10 @@ init_status_t init() {
|
|||
set_clock_config(clock_config_irc);
|
||||
cgu::pll1::disable();
|
||||
|
||||
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
|
||||
* core clock speed to the 110 - 204MHz range.
|
||||
*/
|
||||
set_cpu_clock_speed();
|
||||
|
||||
/* Step into the 90-110MHz M4 clock range */
|
||||
/* OG:
|
||||
* Fclkin = 40M
|
||||
* /N=2 = 20M = PFDin
|
||||
* Fcco = PFDin * (M=10) = 200M
|
||||
* r9:
|
||||
* Fclkin = 10M
|
||||
* /N=1 = 10M = PFDin
|
||||
* Fcco = PFDin * (M=20) = 200M
|
||||
* Fclk = Fcco / (2*(P=1)) = 100M
|
||||
*/
|
||||
cgu::pll1::ctrl({
|
||||
.pd = 1,
|
||||
.bypass = 0,
|
||||
.fbsel = 0,
|
||||
.direct = 0,
|
||||
.psel = 0,
|
||||
.autoblock = 1,
|
||||
.nsel = hackrf_r9 ? 0UL : 1UL,
|
||||
.msel = hackrf_r9 ? 19UL : 9UL,
|
||||
.clk_sel = cgu::CLK_SEL::GP_CLKIN,
|
||||
});
|
||||
|
||||
cgu::pll1::enable();
|
||||
while (!cgu::pll1::is_locked())
|
||||
;
|
||||
|
||||
set_clock_config(clock_config_pll1_step);
|
||||
|
||||
/* Delay >50us at 90-110MHz clock speed */
|
||||
volatile uint32_t delay = 1400;
|
||||
while (delay--)
|
||||
;
|
||||
|
||||
set_clock_config(clock_config_pll1);
|
||||
|
||||
/* Remove /2P divider from PLL1 output to achieve full speed */
|
||||
cgu::pll1::direct();
|
||||
if (lcd_fast_setup)
|
||||
draw_splash_screen_icon(0, ui::bitmap_icon_memory);
|
||||
|
||||
usb_serial.initialize();
|
||||
|
||||
|
@ -474,18 +543,11 @@ init_status_t init() {
|
|||
chThdSleepMilliseconds(10);
|
||||
|
||||
/* Check if portapack is attached by checking if any of the two audio chips is present. */
|
||||
systime_t timeout = 50;
|
||||
uint8_t wm8731_reset_command[] = {0x0f, 0x00};
|
||||
if (i2c0.transmit(0x1a /* wm8731 */, wm8731_reset_command, 2, timeout) == false) {
|
||||
audio_codec_ak4951.reset();
|
||||
uint8_t ak4951_init_command[] = {0x00, 0x00};
|
||||
i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout);
|
||||
chThdSleepMilliseconds(10);
|
||||
if (i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout) == false) {
|
||||
shutdown_base();
|
||||
return init_status_t::INIT_NO_PORTAPACK;
|
||||
}
|
||||
}
|
||||
if (lcd_fast_setup == false && is_portapack_present() == false)
|
||||
return init_status_t::INIT_NO_PORTAPACK;
|
||||
|
||||
if (lcd_fast_setup)
|
||||
draw_splash_screen_icon(1, ui::bitmap_icon_remote);
|
||||
|
||||
touch::adc::init();
|
||||
controls_init();
|
||||
|
@ -501,23 +563,20 @@ init_status_t init() {
|
|||
|
||||
chThdSleepMilliseconds(10);
|
||||
|
||||
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
|
||||
if (result == portapack::cpld::CpldUpdateStatus::Program_failed) {
|
||||
chThdSleepMilliseconds(10);
|
||||
// Mode left (R1) and right (R2,H2,H2+) bypass going into hackrf mode after failing CPLD update
|
||||
// Mode center (autodetect), up (R1) and down (R2,H2,H2+) will go into hackrf mode after failing CPLD update
|
||||
if (load_config() != 3 /* left */ && load_config() != 4 /* right */) {
|
||||
shutdown_base();
|
||||
return init_status_t::INIT_PORTAPACK_CPLD_FAILED;
|
||||
}
|
||||
}
|
||||
if (lcd_fast_setup)
|
||||
draw_splash_screen_icon(2, ui::bitmap_icon_sd);
|
||||
|
||||
init_status_t return_code = init_status_t::INIT_SUCCESS;
|
||||
|
||||
if (!hackrf::cpld::load_sram()) {
|
||||
if (lcd_fast_setup)
|
||||
chDbgPanic("HACKRF CPLD FAILED");
|
||||
|
||||
return_code = init_status_t::INIT_HACKRF_CPLD_FAILED;
|
||||
}
|
||||
|
||||
if (lcd_fast_setup)
|
||||
draw_splash_screen_icon(3, ui::bitmap_icon_hackrf);
|
||||
|
||||
chThdSleepMilliseconds(10); // This delay seems to solve white noise audio issues
|
||||
|
||||
LPC_CREG->DMAMUX = portapack::gpdma_mux;
|
||||
|
@ -527,6 +586,13 @@ init_status_t init() {
|
|||
|
||||
audio::init(portapack_audio_codec());
|
||||
|
||||
if (lcd_fast_setup)
|
||||
draw_splash_screen_icon(4, ui::bitmap_icon_speaker);
|
||||
else {
|
||||
portapack::display.init();
|
||||
portapack::backlight()->on();
|
||||
}
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue