Skip to content

Commit

Permalink
Add portapack cpld write usb serial command for AG256SL100 devices (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
bernd-herzog authored Dec 5, 2024
1 parent c553df7 commit 874eba8
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 2 deletions.
186 changes: 186 additions & 0 deletions firmware/application/usb_serial_shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,191 @@ static void cmd_cpld_read(BaseSequentialStream* chp, int argc, char* argv[]) {
}
}

static uint32_t reverse(uint32_t x) {
x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
x = ((x >> 16) & 0xffffu) | ((x & 0xffffu) << 16);
return x;
}

static void cmd_cpld_write(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage =
"usage: cpld_write <device> <target> <file>\r\n"
" device can be: hackrf, portapack\r\n"
" target can be: sram (hackrf only), eeprom\r\n"
" currently only \"cpld_write portapack eeprom <file>\" is supported\r\n";

if (argc != 3) {
chprintf(chp, usage);
return;
}

if (strncmp(argv[0], "hackrf", 5) == 0) {
chprintf(chp, usage);
} else if (strncmp(argv[0], "portapack", 5) == 0) {
if (strncmp(argv[1], "eeprom", 5) == 0) {
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();

chprintf(chp, "CPLD IDCODE: 0x%08X\r\n", idcode);

if (idcode == 0x00025610) {
chprintf(chp, "CPLD Model: AGM AG256SL100\r\n");

if (cpld.AGM_enter_maintenance_mode() == false) {
return;
}

File* file = new File();
auto path = path_from_string8(argv[2]);
auto error = file->open(path);

if (error.is_valid()) {
chprintf(chp, "Error opening file: %s %d %s\r\n", argv[2], error.value().code(), error.value().what().c_str());
delete file;
cpld.AGM_exit_maintenance_mode();
return;
}

auto data = std::make_unique<std::array<uint32_t, 1801>>();
uint32_t magic = 0;
bool magic_found = false;
uint32_t expected_address = 0;

auto readData = std::vector<uint8_t>();

chprintf(chp, "Reading file...\r\n");
file->seek(0);

while (!file->eof().value()) {
uint32_t remainingData = readData.size();
uint32_t bytesToRead = 512 - remainingData;

readData.resize(512);

auto result = file->read(readData.data() + remainingData, bytesToRead);

if (result.is_error()) {
chprintf(chp, "Error reading file: %d %s\r\n", result.error().code(), result.error().what().c_str());
cpld.AGM_exit_maintenance_mode();
file->close();
delete file;
return;
}

if (result.value() != 512)
readData.resize(remainingData + result.value());

do {
auto it = std::find(readData.begin(), readData.end(), '\n');
if (it != readData.end()) {
std::string line(readData.begin(), it);
readData.erase(readData.begin(), it + 1);

line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());

auto prefix = line.find("sdr 64 -tdi ", 0);
auto suffix = line.find("0040", line.size() - 4);

if (prefix == 0 && suffix == line.size() - 4) {
std::string dataString = line.substr(line.size() - 16, 16);

uint32_t address = reverse(std::stoul(dataString.substr(8, 8), nullptr, 16) - 64) / 4;
uint32_t value = std::stoul(dataString.substr(0, 8), nullptr, 16);

if (expected_address == 299 && address == 0) {
magic = value;
magic_found = true;
chprintf(chp, "Magic found: %08X\r\n", magic);
continue;
}

if (expected_address != address) {
chprintf(chp, "Error: expected address %d, got %d\r\n", expected_address, address);
cpld.AGM_exit_maintenance_mode();
file->close();
delete file;
return;
}

(*data)[expected_address] = value;
expected_address++;

if (expected_address == 1801) {
if (!magic_found) {
chprintf(chp, "Error: magic not found\r\n");
cpld.AGM_exit_maintenance_mode();
file->close();
delete file;
return;
}

chprintf(chp, "Writing data to CPLD...\r\n");
file->close();
delete file;

cpld.AGM_write(*data, magic);

cpld.AGM_enter_read_mode();

CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
for (size_t i = 0; i < 2048; i++) {
uint32_t data = cpld.AGM_read(i);
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.AGM_exit_maintenance_mode();

chprintf(chp, "New CPLD firmware checksum: 0x%08X\r\n", crc.checksum());

m4_request_shutdown();
chThdSleepMilliseconds(1000);

WWDT_MOD = WWDT_MOD_WDEN | WWDT_MOD_WDRESET;
WWDT_TC = 100000 & 0xFFFFFF;
WWDT_FEED_SEQUENCE;

return;
break;
}
}
} else {
break;
}
} while (true);
}

file->close();
delete file;

cpld.AGM_exit_maintenance_mode();

} else {
chprintf(chp, "CPLD Model: unknown\r\n");
}
} else {
chprintf(chp, usage);
}
} else {
chprintf(chp, usage);
}
}

static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotgps <lat> <lon> [altitude] [speed] [satinuse]\r\n";
if (argc < 2 || argc > 5) {
Expand Down Expand Up @@ -1203,6 +1388,7 @@ static const ShellCommand commands[] = {
{"rtcset", cmd_rtcset},
{"cpld_info", cpld_info},
{"cpld_read", cmd_cpld_read},
{"cpld_write", cmd_cpld_write},
{"accessibility_readall", cmd_accessibility_readall},
{"accessibility_readcurr", cmd_accessibility_readcurr},
{"applist", cmd_applist},
Expand Down
35 changes: 35 additions & 0 deletions firmware/common/cpld_max5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,5 +332,40 @@ uint32_t CPLD::AGM_read(uint32_t address) {
return jtag.shift_dr(32, encoded_address, 0x0);
}

void CPLD::AGM_write(const std::array<uint32_t, 1801>& block, uint32_t magic_value) {
shift_ir(instruction_t::AGM_SET_REGISTER);
jtag.runtest_tck(100);
jtag.shift_dr(8, 0xf0);
jtag.runtest_tck(100);

shift_ir(instruction_t::AGM_ERASE);
jtag.runtest_tck(100);
jtag.runtest_ms(500);

shift_ir(instruction_t::AGM_SET_REGISTER);
jtag.runtest_tck(100);
jtag.shift_dr(8, 0xf0);
jtag.runtest_tck(100);

shift_ir(instruction_t::AGM_PROGRAM);
jtag.runtest_tck(100);

auto data = block.data();
for (size_t i = 0; i < 0x12B; i++) {
auto address = AGM_encode_address(i * 4, 0x40);
jtag.shift_dr(32, address, data[i]);
jtag.runtest_ms(2);
}

jtag.shift_dr(32, 0x00000040, magic_value);
jtag.runtest_ms(2);

for (size_t i = 0x12B; i < block.size(); i++) {
auto address = AGM_encode_address(i * 4, 0x40);
jtag.shift_dr(32, address, data[i]);
jtag.runtest_ms(2);
}
}

} /* namespace max5 */
} /* namespace cpld */
1 change: 1 addition & 0 deletions firmware/common/cpld_max5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class CPLD {
void AGM_enter_read_mode();
uint32_t AGM_encode_address(uint32_t address, uint32_t trailer);
uint32_t AGM_read(uint32_t address);
void AGM_write(const std::array<uint32_t, 1801>& block, uint32_t magic_value);

private:
using idcode_t = uint32_t;
Expand Down
12 changes: 11 additions & 1 deletion firmware/common/jtag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define __JTAG_H__

#include "jtag_target.hpp"
#include "ch.h"

#include <cstdint>
#include <cstddef>
Expand Down Expand Up @@ -51,7 +52,16 @@ class JTAG {
}

void runtest_tck(const size_t count) {
target.delay(count);
for (size_t i = 0; i < count; i++) {
target.clock(0, 0);
}
}

void runtest_ms(const size_t count) {
auto starttime = chTimeNow();

while ((chTimeNow() - starttime) < (count + 1))
target.clock(0, 0);
}

uint32_t shift_ir(const size_t count, const uint32_t value) {
Expand Down
6 changes: 5 additions & 1 deletion firmware/common/message_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ class MessageQueue {
}

bool push(const void* const buf, const size_t len) {
chMtxLock(&mutex_write);
bool lock_success = chMtxTryLock(&mutex_write);
if (!lock_success) {
return false;
}

const auto result = fifo.in_r(buf, len);
chMtxUnlock();

Expand Down

0 comments on commit 874eba8

Please sign in to comment.