Skip to content

Commit 874eba8

Browse files
authored
Add portapack cpld write usb serial command for AG256SL100 devices (#2401)
1 parent c553df7 commit 874eba8

File tree

5 files changed

+238
-2
lines changed

5 files changed

+238
-2
lines changed

firmware/application/usb_serial_shell.cpp

+186
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,191 @@ static void cmd_cpld_read(BaseSequentialStream* chp, int argc, char* argv[]) {
907907
}
908908
}
909909

910+
static uint32_t reverse(uint32_t x) {
911+
x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
912+
x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
913+
x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
914+
x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
915+
x = ((x >> 16) & 0xffffu) | ((x & 0xffffu) << 16);
916+
return x;
917+
}
918+
919+
static void cmd_cpld_write(BaseSequentialStream* chp, int argc, char* argv[]) {
920+
const char* usage =
921+
"usage: cpld_write <device> <target> <file>\r\n"
922+
" device can be: hackrf, portapack\r\n"
923+
" target can be: sram (hackrf only), eeprom\r\n"
924+
" currently only \"cpld_write portapack eeprom <file>\" is supported\r\n";
925+
926+
if (argc != 3) {
927+
chprintf(chp, usage);
928+
return;
929+
}
930+
931+
if (strncmp(argv[0], "hackrf", 5) == 0) {
932+
chprintf(chp, usage);
933+
} else if (strncmp(argv[0], "portapack", 5) == 0) {
934+
if (strncmp(argv[1], "eeprom", 5) == 0) {
935+
jtag::GPIOTarget target{
936+
portapack::gpio_cpld_tck,
937+
portapack::gpio_cpld_tms,
938+
portapack::gpio_cpld_tdi,
939+
portapack::gpio_cpld_tdo};
940+
jtag::JTAG jtag{target};
941+
portapack::cpld::CPLD cpld{jtag};
942+
943+
cpld.reset();
944+
cpld.run_test_idle();
945+
uint32_t idcode = cpld.get_idcode();
946+
947+
chprintf(chp, "CPLD IDCODE: 0x%08X\r\n", idcode);
948+
949+
if (idcode == 0x00025610) {
950+
chprintf(chp, "CPLD Model: AGM AG256SL100\r\n");
951+
952+
if (cpld.AGM_enter_maintenance_mode() == false) {
953+
return;
954+
}
955+
956+
File* file = new File();
957+
auto path = path_from_string8(argv[2]);
958+
auto error = file->open(path);
959+
960+
if (error.is_valid()) {
961+
chprintf(chp, "Error opening file: %s %d %s\r\n", argv[2], error.value().code(), error.value().what().c_str());
962+
delete file;
963+
cpld.AGM_exit_maintenance_mode();
964+
return;
965+
}
966+
967+
auto data = std::make_unique<std::array<uint32_t, 1801>>();
968+
uint32_t magic = 0;
969+
bool magic_found = false;
970+
uint32_t expected_address = 0;
971+
972+
auto readData = std::vector<uint8_t>();
973+
974+
chprintf(chp, "Reading file...\r\n");
975+
file->seek(0);
976+
977+
while (!file->eof().value()) {
978+
uint32_t remainingData = readData.size();
979+
uint32_t bytesToRead = 512 - remainingData;
980+
981+
readData.resize(512);
982+
983+
auto result = file->read(readData.data() + remainingData, bytesToRead);
984+
985+
if (result.is_error()) {
986+
chprintf(chp, "Error reading file: %d %s\r\n", result.error().code(), result.error().what().c_str());
987+
cpld.AGM_exit_maintenance_mode();
988+
file->close();
989+
delete file;
990+
return;
991+
}
992+
993+
if (result.value() != 512)
994+
readData.resize(remainingData + result.value());
995+
996+
do {
997+
auto it = std::find(readData.begin(), readData.end(), '\n');
998+
if (it != readData.end()) {
999+
std::string line(readData.begin(), it);
1000+
readData.erase(readData.begin(), it + 1);
1001+
1002+
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
1003+
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
1004+
1005+
auto prefix = line.find("sdr 64 -tdi ", 0);
1006+
auto suffix = line.find("0040", line.size() - 4);
1007+
1008+
if (prefix == 0 && suffix == line.size() - 4) {
1009+
std::string dataString = line.substr(line.size() - 16, 16);
1010+
1011+
uint32_t address = reverse(std::stoul(dataString.substr(8, 8), nullptr, 16) - 64) / 4;
1012+
uint32_t value = std::stoul(dataString.substr(0, 8), nullptr, 16);
1013+
1014+
if (expected_address == 299 && address == 0) {
1015+
magic = value;
1016+
magic_found = true;
1017+
chprintf(chp, "Magic found: %08X\r\n", magic);
1018+
continue;
1019+
}
1020+
1021+
if (expected_address != address) {
1022+
chprintf(chp, "Error: expected address %d, got %d\r\n", expected_address, address);
1023+
cpld.AGM_exit_maintenance_mode();
1024+
file->close();
1025+
delete file;
1026+
return;
1027+
}
1028+
1029+
(*data)[expected_address] = value;
1030+
expected_address++;
1031+
1032+
if (expected_address == 1801) {
1033+
if (!magic_found) {
1034+
chprintf(chp, "Error: magic not found\r\n");
1035+
cpld.AGM_exit_maintenance_mode();
1036+
file->close();
1037+
delete file;
1038+
return;
1039+
}
1040+
1041+
chprintf(chp, "Writing data to CPLD...\r\n");
1042+
file->close();
1043+
delete file;
1044+
1045+
cpld.AGM_write(*data, magic);
1046+
1047+
cpld.AGM_enter_read_mode();
1048+
1049+
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
1050+
for (size_t i = 0; i < 2048; i++) {
1051+
uint32_t data = cpld.AGM_read(i);
1052+
crc.process_byte((data >> 0) & 0xff);
1053+
crc.process_byte((data >> 8) & 0xff);
1054+
crc.process_byte((data >> 16) & 0xff);
1055+
crc.process_byte((data >> 24) & 0xff);
1056+
}
1057+
1058+
cpld.AGM_exit_maintenance_mode();
1059+
1060+
chprintf(chp, "New CPLD firmware checksum: 0x%08X\r\n", crc.checksum());
1061+
1062+
m4_request_shutdown();
1063+
chThdSleepMilliseconds(1000);
1064+
1065+
WWDT_MOD = WWDT_MOD_WDEN | WWDT_MOD_WDRESET;
1066+
WWDT_TC = 100000 & 0xFFFFFF;
1067+
WWDT_FEED_SEQUENCE;
1068+
1069+
return;
1070+
break;
1071+
}
1072+
}
1073+
} else {
1074+
break;
1075+
}
1076+
} while (true);
1077+
}
1078+
1079+
file->close();
1080+
delete file;
1081+
1082+
cpld.AGM_exit_maintenance_mode();
1083+
1084+
} else {
1085+
chprintf(chp, "CPLD Model: unknown\r\n");
1086+
}
1087+
} else {
1088+
chprintf(chp, usage);
1089+
}
1090+
} else {
1091+
chprintf(chp, usage);
1092+
}
1093+
}
1094+
9101095
static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
9111096
const char* usage = "usage: gotgps <lat> <lon> [altitude] [speed] [satinuse]\r\n";
9121097
if (argc < 2 || argc > 5) {
@@ -1203,6 +1388,7 @@ static const ShellCommand commands[] = {
12031388
{"rtcset", cmd_rtcset},
12041389
{"cpld_info", cpld_info},
12051390
{"cpld_read", cmd_cpld_read},
1391+
{"cpld_write", cmd_cpld_write},
12061392
{"accessibility_readall", cmd_accessibility_readall},
12071393
{"accessibility_readcurr", cmd_accessibility_readcurr},
12081394
{"applist", cmd_applist},

firmware/common/cpld_max5.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -332,5 +332,40 @@ uint32_t CPLD::AGM_read(uint32_t address) {
332332
return jtag.shift_dr(32, encoded_address, 0x0);
333333
}
334334

335+
void CPLD::AGM_write(const std::array<uint32_t, 1801>& block, uint32_t magic_value) {
336+
shift_ir(instruction_t::AGM_SET_REGISTER);
337+
jtag.runtest_tck(100);
338+
jtag.shift_dr(8, 0xf0);
339+
jtag.runtest_tck(100);
340+
341+
shift_ir(instruction_t::AGM_ERASE);
342+
jtag.runtest_tck(100);
343+
jtag.runtest_ms(500);
344+
345+
shift_ir(instruction_t::AGM_SET_REGISTER);
346+
jtag.runtest_tck(100);
347+
jtag.shift_dr(8, 0xf0);
348+
jtag.runtest_tck(100);
349+
350+
shift_ir(instruction_t::AGM_PROGRAM);
351+
jtag.runtest_tck(100);
352+
353+
auto data = block.data();
354+
for (size_t i = 0; i < 0x12B; i++) {
355+
auto address = AGM_encode_address(i * 4, 0x40);
356+
jtag.shift_dr(32, address, data[i]);
357+
jtag.runtest_ms(2);
358+
}
359+
360+
jtag.shift_dr(32, 0x00000040, magic_value);
361+
jtag.runtest_ms(2);
362+
363+
for (size_t i = 0x12B; i < block.size(); i++) {
364+
auto address = AGM_encode_address(i * 4, 0x40);
365+
jtag.shift_dr(32, address, data[i]);
366+
jtag.runtest_ms(2);
367+
}
368+
}
369+
335370
} /* namespace max5 */
336371
} /* namespace cpld */

firmware/common/cpld_max5.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class CPLD {
9999
void AGM_enter_read_mode();
100100
uint32_t AGM_encode_address(uint32_t address, uint32_t trailer);
101101
uint32_t AGM_read(uint32_t address);
102+
void AGM_write(const std::array<uint32_t, 1801>& block, uint32_t magic_value);
102103

103104
private:
104105
using idcode_t = uint32_t;

firmware/common/jtag.hpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define __JTAG_H__
2424

2525
#include "jtag_target.hpp"
26+
#include "ch.h"
2627

2728
#include <cstdint>
2829
#include <cstddef>
@@ -51,7 +52,16 @@ class JTAG {
5152
}
5253

5354
void runtest_tck(const size_t count) {
54-
target.delay(count);
55+
for (size_t i = 0; i < count; i++) {
56+
target.clock(0, 0);
57+
}
58+
}
59+
60+
void runtest_ms(const size_t count) {
61+
auto starttime = chTimeNow();
62+
63+
while ((chTimeNow() - starttime) < (count + 1))
64+
target.clock(0, 0);
5565
}
5666

5767
uint32_t shift_ir(const size_t count, const uint32_t value) {

firmware/common/message_queue.hpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ class MessageQueue {
101101
}
102102

103103
bool push(const void* const buf, const size_t len) {
104-
chMtxLock(&mutex_write);
104+
bool lock_success = chMtxTryLock(&mutex_write);
105+
if (!lock_success) {
106+
return false;
107+
}
108+
105109
const auto result = fifo.in_r(buf, len);
106110
chMtxUnlock();
107111

0 commit comments

Comments
 (0)