mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -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
@ -162,6 +162,8 @@ static void event_loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
|
||||||
|
|
||||||
if (config_mode_should_enter()) {
|
if (config_mode_should_enter()) {
|
||||||
config_mode_clear();
|
config_mode_clear();
|
||||||
config_mode_run();
|
config_mode_run();
|
||||||
@ -169,15 +171,13 @@ int main(void) {
|
|||||||
|
|
||||||
config_mode_set();
|
config_mode_set();
|
||||||
|
|
||||||
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
|
|
||||||
|
|
||||||
switch (portapack::init()) {
|
switch (portapack::init()) {
|
||||||
case portapack::init_status_t::INIT_HACKRF_CPLD_FAILED:
|
case portapack::init_status_t::INIT_HACKRF_CPLD_FAILED:
|
||||||
portapack::init_error = "HACKRF CPLD FAILED";
|
portapack::init_error = "HACKRF CPLD FAILED";
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case portapack::init_status_t::INIT_SUCCESS:
|
case portapack::init_status_t::INIT_SUCCESS:
|
||||||
portapack::display.init();
|
|
||||||
config_mode_clear();
|
config_mode_clear();
|
||||||
|
|
||||||
lcd_frame_sync_configure();
|
lcd_frame_sync_configure();
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
using namespace hackrf::one;
|
using namespace hackrf::one;
|
||||||
|
#include "jtag_target_gpio.hpp"
|
||||||
|
|
||||||
#include "clock_manager.hpp"
|
#include "clock_manager.hpp"
|
||||||
#include "event_m0.hpp"
|
#include "event_m0.hpp"
|
||||||
@ -50,6 +51,7 @@ using asahi_kasei::ak4951::AK4951;
|
|||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
#include "sd_card.hpp"
|
#include "sd_card.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
#include "bitmap.hpp"
|
||||||
|
|
||||||
namespace portapack {
|
namespace portapack {
|
||||||
|
|
||||||
@ -174,50 +176,21 @@ constexpr I2CConfig i2c_config_fast_clock{
|
|||||||
enum class PortaPackModel {
|
enum class PortaPackModel {
|
||||||
R1_20150901,
|
R1_20150901,
|
||||||
R2_20170522,
|
R2_20170522,
|
||||||
|
AGM,
|
||||||
|
AUTODETECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool save_config(int8_t value) {
|
static bool save_config(int8_t value) {
|
||||||
persistent_memory::set_config_cpld(value);
|
persistent_memory::set_config_cpld(value);
|
||||||
if (sd_card::status() == sd_card::Status::Mounted) {
|
portapack::persistent_memory::cache::persist();
|
||||||
ensure_directory("/hardware");
|
|
||||||
File file;
|
|
||||||
auto sucess = file.create("/hardware/settings.txt");
|
|
||||||
if (!sucess.is_valid()) {
|
|
||||||
file.write_line(to_string_dec_uint(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
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 int load_config() {
|
||||||
static Optional<int> config_value;
|
static Optional<int> config_value;
|
||||||
if (!config_value.is_valid()) {
|
if (!config_value.is_valid()) {
|
||||||
int8_t value = portapack::persistent_memory::config_cpld();
|
int8_t value = portapack::persistent_memory::config_cpld();
|
||||||
if ((value <= 0 || value >= 5) && sd_card::status() == sd_card::Status::Mounted) {
|
config_value = value;
|
||||||
int data = read_file("/hardware/settings.txt");
|
|
||||||
if (data != -1) {
|
|
||||||
config_value = data;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
config_value = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return config_value.value();
|
return config_value.value();
|
||||||
}
|
}
|
||||||
@ -226,39 +199,49 @@ static PortaPackModel portapack_model() {
|
|||||||
static Optional<PortaPackModel> model;
|
static Optional<PortaPackModel> model;
|
||||||
|
|
||||||
if (!model.is_valid()) {
|
if (!model.is_valid()) {
|
||||||
const auto switches_state = get_switches_state();
|
jtag::GPIOTarget target{
|
||||||
// Only save config if no other multi key boot action is triggered (like pmem reset)
|
portapack::gpio_cpld_tck,
|
||||||
if (switches_state.count() == 1) {
|
portapack::gpio_cpld_tms,
|
||||||
if (switches_state[(size_t)ui::KeyEvent::Up]) {
|
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);
|
save_config(1);
|
||||||
// model = PortaPackModel::R2_20170522; // Commented these out as they should be set down below anyway
|
// 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);
|
save_config(2);
|
||||||
// model = PortaPackModel::R1_20150901;
|
// 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);
|
save_config(3);
|
||||||
// model = PortaPackModel::R1_20150901;
|
// 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);
|
save_config(4);
|
||||||
// model = PortaPackModel::R2_20170522;
|
// 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);
|
save_config(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (load_config() == 1) {
|
if (load_config() == 1) {
|
||||||
model = PortaPackModel::R2_20170522;
|
model = PortaPackModel::R2_20170522;
|
||||||
} else if (load_config() == 2) {
|
} else if (load_config() == 2) {
|
||||||
model = PortaPackModel::R1_20150901;
|
model = PortaPackModel::R1_20150901;
|
||||||
} else if (load_config() == 3) {
|
} else if (load_config() == 3) {
|
||||||
model = PortaPackModel::R1_20150901;
|
model = PortaPackModel::R1_20150901;
|
||||||
} else if (load_config() == 4) {
|
} else if (load_config() == 4) {
|
||||||
model = PortaPackModel::R2_20170522;
|
model = PortaPackModel::R2_20170522;
|
||||||
} else {
|
|
||||||
if (audio_codec_wm8731.detected()) {
|
|
||||||
model = PortaPackModel::R1_20150901; // H1R1
|
|
||||||
} else {
|
} else {
|
||||||
model = PortaPackModel::R2_20170522; // H1R2, H2, H2+
|
model = PortaPackModel::AUTODETECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,6 +328,129 @@ static void shutdown_base() {
|
|||||||
clock_manager.shutdown();
|
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:
|
/* Clock scheme after exiting bootloader in SPIFI mode:
|
||||||
*
|
*
|
||||||
* XTAL_OSC = powered down
|
* XTAL_OSC = powered down
|
||||||
@ -396,23 +502,24 @@ init_status_t init() {
|
|||||||
|
|
||||||
i2c0.start(i2c_config_boot_clock);
|
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);
|
chThdSleepMilliseconds(100);
|
||||||
|
|
||||||
configure_pins_portapack();
|
configure_pins_portapack();
|
||||||
|
|
||||||
portapack::io.init();
|
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. */
|
/* Cache some configuration data from persistent memory. */
|
||||||
persistent_memory::cache::init();
|
|
||||||
rtc_time::dst_init();
|
rtc_time::dst_init();
|
||||||
chThdSleepMilliseconds(10);
|
chThdSleepMilliseconds(10);
|
||||||
|
|
||||||
@ -425,48 +532,10 @@ init_status_t init() {
|
|||||||
set_clock_config(clock_config_irc);
|
set_clock_config(clock_config_irc);
|
||||||
cgu::pll1::disable();
|
cgu::pll1::disable();
|
||||||
|
|
||||||
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
|
set_cpu_clock_speed();
|
||||||
* core clock speed to the 110 - 204MHz range.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Step into the 90-110MHz M4 clock range */
|
if (lcd_fast_setup)
|
||||||
/* OG:
|
draw_splash_screen_icon(0, ui::bitmap_icon_memory);
|
||||||
* 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();
|
|
||||||
|
|
||||||
usb_serial.initialize();
|
usb_serial.initialize();
|
||||||
|
|
||||||
@ -474,18 +543,11 @@ init_status_t init() {
|
|||||||
chThdSleepMilliseconds(10);
|
chThdSleepMilliseconds(10);
|
||||||
|
|
||||||
/* Check if portapack is attached by checking if any of the two audio chips is present. */
|
/* Check if portapack is attached by checking if any of the two audio chips is present. */
|
||||||
systime_t timeout = 50;
|
if (lcd_fast_setup == false && is_portapack_present() == false)
|
||||||
uint8_t wm8731_reset_command[] = {0x0f, 0x00};
|
return init_status_t::INIT_NO_PORTAPACK;
|
||||||
if (i2c0.transmit(0x1a /* wm8731 */, wm8731_reset_command, 2, timeout) == false) {
|
|
||||||
audio_codec_ak4951.reset();
|
if (lcd_fast_setup)
|
||||||
uint8_t ak4951_init_command[] = {0x00, 0x00};
|
draw_splash_screen_icon(1, ui::bitmap_icon_remote);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
touch::adc::init();
|
touch::adc::init();
|
||||||
controls_init();
|
controls_init();
|
||||||
@ -501,23 +563,20 @@ init_status_t init() {
|
|||||||
|
|
||||||
chThdSleepMilliseconds(10);
|
chThdSleepMilliseconds(10);
|
||||||
|
|
||||||
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
|
if (lcd_fast_setup)
|
||||||
if (result == portapack::cpld::CpldUpdateStatus::Program_failed) {
|
draw_splash_screen_icon(2, ui::bitmap_icon_sd);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init_status_t return_code = init_status_t::INIT_SUCCESS;
|
init_status_t return_code = init_status_t::INIT_SUCCESS;
|
||||||
|
|
||||||
if (!hackrf::cpld::load_sram()) {
|
if (!hackrf::cpld::load_sram()) {
|
||||||
|
if (lcd_fast_setup)
|
||||||
|
chDbgPanic("HACKRF CPLD FAILED");
|
||||||
|
|
||||||
return_code = init_status_t::INIT_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
|
chThdSleepMilliseconds(10); // This delay seems to solve white noise audio issues
|
||||||
|
|
||||||
LPC_CREG->DMAMUX = portapack::gpdma_mux;
|
LPC_CREG->DMAMUX = portapack::gpdma_mux;
|
||||||
@ -527,6 +586,13 @@ init_status_t init() {
|
|||||||
|
|
||||||
audio::init(portapack_audio_codec());
|
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;
|
return return_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "hackrf_gpio.hpp"
|
#include "hackrf_gpio.hpp"
|
||||||
#include "portapack_hal.hpp"
|
#include "portapack_hal.hpp"
|
||||||
|
#include "portapack.hpp"
|
||||||
|
|
||||||
#include "jtag_target_gpio.hpp"
|
#include "jtag_target_gpio.hpp"
|
||||||
#include "cpld_max5.hpp"
|
#include "cpld_max5.hpp"
|
||||||
@ -30,11 +31,15 @@
|
|||||||
#include "portapack_cpld_data.hpp"
|
#include "portapack_cpld_data.hpp"
|
||||||
#include "hackrf_cpld_data.hpp"
|
#include "hackrf_cpld_data.hpp"
|
||||||
|
|
||||||
|
#include "crc.hpp"
|
||||||
|
|
||||||
|
#define REV_20150901_CHECKSUM 0xE0EF80FB
|
||||||
|
#define REV_20170522_CHECKSUM 0xD1BEB722
|
||||||
|
|
||||||
namespace portapack {
|
namespace portapack {
|
||||||
namespace cpld {
|
namespace cpld {
|
||||||
|
|
||||||
CpldUpdateStatus update_if_necessary(
|
CpldUpdateStatus update_if_necessary(const Config config) {
|
||||||
const Config config) {
|
|
||||||
jtag::GPIOTarget target{
|
jtag::GPIOTarget target{
|
||||||
portapack::gpio_cpld_tck,
|
portapack::gpio_cpld_tck,
|
||||||
portapack::gpio_cpld_tms,
|
portapack::gpio_cpld_tms,
|
||||||
@ -87,6 +92,121 @@ CpldUpdateStatus update_if_necessary(
|
|||||||
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
|
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CpldUpdateStatus enter_maintenance_mode(CPLD& cpld) {
|
||||||
|
/* Unknown state */
|
||||||
|
cpld.reset();
|
||||||
|
cpld.run_test_idle();
|
||||||
|
|
||||||
|
/* Run-Test/Idle */
|
||||||
|
if (!cpld.idcode_ok()) {
|
||||||
|
return CpldUpdateStatus::Idcode_check_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpld.sample();
|
||||||
|
cpld.bypass();
|
||||||
|
cpld.enable();
|
||||||
|
|
||||||
|
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
|
||||||
|
* in passive state.
|
||||||
|
*/
|
||||||
|
if (!cpld.silicon_id_ok()) {
|
||||||
|
return CpldUpdateStatus::Silicon_id_check_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CpldUpdateStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_maintenance_mode(CPLD& cpld) {
|
||||||
|
cpld.disable();
|
||||||
|
cpld.bypass();
|
||||||
|
|
||||||
|
/* Initiate SRAM reload from flash we just programmed. */
|
||||||
|
cpld.sample();
|
||||||
|
cpld.clamp();
|
||||||
|
cpld.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t get_firmware_crc(CPLD& cpld) {
|
||||||
|
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
|
||||||
|
cpld.prepare_read(0x0000);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3328; i++) {
|
||||||
|
uint16_t data = cpld.read();
|
||||||
|
crc.process_byte((data >> 0) & 0xff);
|
||||||
|
crc.process_byte((data >> 8) & 0xff);
|
||||||
|
crc.process_byte((data >> 16) & 0xff);
|
||||||
|
crc.process_byte((data >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpld.prepare_read(0x0001);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 512; i++) {
|
||||||
|
uint16_t data = cpld.read();
|
||||||
|
crc.process_byte((data >> 0) & 0xff);
|
||||||
|
crc.process_byte((data >> 8) & 0xff);
|
||||||
|
crc.process_byte((data >> 16) & 0xff);
|
||||||
|
crc.process_byte((data >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc.checksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
CpldUpdateStatus update_autodetect(const Config config_rev_20150901, const Config config_rev_20170522) {
|
||||||
|
jtag::GPIOTarget target{
|
||||||
|
portapack::gpio_cpld_tck,
|
||||||
|
portapack::gpio_cpld_tms,
|
||||||
|
portapack::gpio_cpld_tdi,
|
||||||
|
portapack::gpio_cpld_tdo};
|
||||||
|
jtag::JTAG jtag{target};
|
||||||
|
CPLD cpld{jtag};
|
||||||
|
|
||||||
|
if (portapack::display.read_display_status())
|
||||||
|
return CpldUpdateStatus::Success; // LCD is ready
|
||||||
|
|
||||||
|
CpldUpdateStatus result = enter_maintenance_mode(cpld);
|
||||||
|
if (result != CpldUpdateStatus::Success)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
uint32_t checksum = get_firmware_crc(cpld);
|
||||||
|
|
||||||
|
if (checksum == REV_20170522_CHECKSUM) {
|
||||||
|
// H2 firmware present
|
||||||
|
if (!cpld.program(config_rev_20150901.block_0, config_rev_20150901.block_1))
|
||||||
|
return CpldUpdateStatus::Program_failed;
|
||||||
|
} else if (checksum == REV_20150901_CHECKSUM) {
|
||||||
|
// H1 firmware present
|
||||||
|
if (!cpld.program(config_rev_20170522.block_0, config_rev_20170522.block_1))
|
||||||
|
return CpldUpdateStatus::Program_failed;
|
||||||
|
} else {
|
||||||
|
// no firmware present
|
||||||
|
if (!cpld.program(config_rev_20150901.block_0, config_rev_20150901.block_1))
|
||||||
|
return CpldUpdateStatus::Program_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_maintenance_mode(cpld);
|
||||||
|
|
||||||
|
if (portapack::display.read_display_status())
|
||||||
|
return CpldUpdateStatus::Success; // LCD is ready
|
||||||
|
|
||||||
|
if (checksum != REV_20150901_CHECKSUM && checksum != REV_20170522_CHECKSUM) {
|
||||||
|
// try the other one
|
||||||
|
CpldUpdateStatus result = enter_maintenance_mode(cpld);
|
||||||
|
|
||||||
|
if (result != CpldUpdateStatus::Success)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (!cpld.program(config_rev_20170522.block_0, config_rev_20170522.block_1))
|
||||||
|
return CpldUpdateStatus::Program_failed;
|
||||||
|
|
||||||
|
exit_maintenance_mode(cpld);
|
||||||
|
|
||||||
|
if (portapack::display.read_display_status())
|
||||||
|
return CpldUpdateStatus::Success; // LCD is ready
|
||||||
|
}
|
||||||
|
|
||||||
|
return CpldUpdateStatus::Program_failed;
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace cpld */
|
} /* namespace cpld */
|
||||||
} /* namespace portapack */
|
} /* namespace portapack */
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ enum class CpldUpdateStatus {
|
|||||||
Program_failed = 3
|
Program_failed = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
CpldUpdateStatus update_if_necessary(
|
CpldUpdateStatus update_if_necessary(const Config config);
|
||||||
const Config config);
|
CpldUpdateStatus update_autodetect(const Config config_rev_20150901, const Config config_rev_20170522);
|
||||||
|
|
||||||
} /* namespace cpld */
|
} /* namespace cpld */
|
||||||
} /* namespace portapack */
|
} /* namespace portapack */
|
||||||
|
@ -84,6 +84,17 @@ void lcd_wake() {
|
|||||||
lcd_display_on();
|
lcd_display_on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t lcd_read_display_status() {
|
||||||
|
io.lcd_data_write_command_and_data(0x09, {});
|
||||||
|
io.lcd_read_word();
|
||||||
|
|
||||||
|
uint32_t value2 = io.lcd_read_word();
|
||||||
|
uint32_t value3 = io.lcd_read_word();
|
||||||
|
uint32_t value4 = io.lcd_read_word();
|
||||||
|
uint32_t value5 = io.lcd_read_word();
|
||||||
|
return value5 + (value4 << 8) + (value3 << 16) + (value2 << 24);
|
||||||
|
}
|
||||||
|
|
||||||
void lcd_init() {
|
void lcd_init() {
|
||||||
// LCDs are configured for IM[2:0] = 001
|
// LCDs are configured for IM[2:0] = 001
|
||||||
// 8080-I system, 16-bit parallel bus
|
// 8080-I system, 16-bit parallel bus
|
||||||
@ -260,6 +271,25 @@ void lcd_vertical_scrolling_start_address(
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
bool ILI9341::read_display_status() {
|
||||||
|
lcd_reset();
|
||||||
|
uint32_t display_status = lcd_read_display_status();
|
||||||
|
|
||||||
|
/* This tries to validate the display_status.
|
||||||
|
* The value could vary from device to device, so we are less specific here.
|
||||||
|
* 0xFFFFFEFF was seen when the display was not reachable
|
||||||
|
* 0x00610000 was seen when the display was reachable
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (display_status > 0x0E000000ULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (display_status < 0x00000100ULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ILI9341::init() {
|
void ILI9341::init() {
|
||||||
lcd_reset();
|
lcd_reset();
|
||||||
lcd_init();
|
lcd_init();
|
||||||
|
@ -42,6 +42,8 @@ class ILI9341 {
|
|||||||
ILI9341(ILI9341&&) = delete;
|
ILI9341(ILI9341&&) = delete;
|
||||||
void operator=(const ILI9341&) = delete;
|
void operator=(const ILI9341&) = delete;
|
||||||
|
|
||||||
|
bool read_display_status();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
@ -430,13 +430,15 @@ void defaults() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
const auto switches_state = get_switches_state();
|
const auto switches_state = swizzled_switches();
|
||||||
|
|
||||||
// ignore for valid check
|
// ignore for valid check
|
||||||
auto config_mode_backup = config_mode_storage_direct();
|
auto config_mode_backup = config_mode_storage_direct();
|
||||||
set_config_mode_storage_direct(CONFIG_MODE_NORMAL_VALUE);
|
set_config_mode_storage_direct(CONFIG_MODE_NORMAL_VALUE);
|
||||||
|
|
||||||
if (!(switches_state[(size_t)ui::KeyEvent::Left] && switches_state[(size_t)ui::KeyEvent::Right]) && backup_ram->is_valid()) {
|
if (!(((switches_state >> (size_t)ui::KeyEvent::Left & 1) == 1) &&
|
||||||
|
((switches_state >> (size_t)ui::KeyEvent::Right & 1) == 1)) &&
|
||||||
|
backup_ram->is_valid()) {
|
||||||
// Copy valid persistent data into cache.
|
// Copy valid persistent data into cache.
|
||||||
cached_backup_ram = *backup_ram;
|
cached_backup_ram = *backup_ram;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user